aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarius Vlad <marius.vlad@collabora.com>2020-10-15 14:52:27 +0300
committerMarius Vlad <marius.vlad@collabora.com>2020-12-01 13:07:53 +0200
commite6ad86a86fe3ed73cac6478e07eb1220399ace1f (patch)
tree58beffdda0ac9fce19432709a79c7c46ce300890
parente0c6ec4cf049522b662874f069244b5c19229906 (diff)
Init waltham-receiver
Bug-AGL: SPEC-3605 Signed-off-by: Marius Vlad <marius.vlad@collabora.com> Change-Id: Ia352702d0c43f1f2ccecbffea85f3d0f17f2fd56
-rw-r--r--.gitreview5
-rw-r--r--COPYING22
-rw-r--r--README.md97
-rw-r--r--config/receiver_pipeline_example_general.cfg1
-rw-r--r--config/receiver_pipeline_example_intel.cfg1
-rw-r--r--config/receiver_pipeline_example_rcar.cfg1
-rw-r--r--include/bitmap.h35
-rw-r--r--include/os-compatibility.h58
-rw-r--r--include/wth-receiver-buffer.h51
-rw-r--r--include/wth-receiver-comm.h305
-rw-r--r--include/wth-receiver-seat.h263
-rw-r--r--include/wth-receiver-surface.h44
-rw-r--r--meson.build149
-rw-r--r--meson_options.txt7
-rw-r--r--src/bitmap.c107
-rw-r--r--src/os-compatibility.c204
-rw-r--r--src/wth-receiver-buffer.c95
-rw-r--r--src/wth-receiver-comm.c453
-rw-r--r--src/wth-receiver-gst-egl.c1012
-rw-r--r--src/wth-receiver-gst-shm.c847
-rw-r--r--src/wth-receiver-main.c306
-rw-r--r--src/wth-receiver-seat.c311
-rw-r--r--src/wth-receiver-surface.c291
23 files changed, 4665 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..c14ce8b
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.automotivelinux.org
+port=29418
+project=apps/waltham-receiver
+defaultbranch=master
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..74eaa45
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+Copyright © 2020 Collabora, Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..76abc66
--- /dev/null
+++ b/README.md
@@ -0,0 +1,97 @@
+# Waltham-receiver
+
+waltham-receiver component is a receiver side implementation for using Waltham
+protocol to obtain and process remote output received from remoting-pluging
+instantianted/created output by the compositor.
+
+This component is designed to be used for evaluating the functionalities of
+waltham-transmitter plugin.
+
+This component also acts as weston client application to display/handle various
+requests from actual weston client at transmitter side.
+
+### Architecture
+
+````
+
+ ECU 1 ECU 2
+ +-----------------------------------------------------+ +----------------------------------------------+
+ | +-----------------+ | | |
+ | | IVI-Application | | | +-----------+-----------+ |
+ | +-----------------+ | | | Gstreamer | | |
+ | ^ | Buffer -----------------------> (Decode) | | |
+ | wayland | +----------------------/ | +-----------+ | |
+ | v | | (Ethernet) | | Waltham-receiver | |
+ | +----+---------------------+ | | ----------------------------> | |
+ | | | Transmitter Plugin |<-----------------------------/ | +-----------------------+ |
+ | | | | | | Waltham-Protocol | ^ |
+ | | |---------------------| | | | wayland | |
+ | | | (remoting-plugin) |------------+ | | v |
+ | | | | | | +---------------------+ |
+ | | +-+-------------------+ | | | | |
+ | | | | | | compositor | |
+ | | compositor | | | | | |
+ | +------+-------------------+ | | +----------------+----+ |
+ | | | | | |
+ | v | | v |
+ | +------------+ | | +----------+ |
+ | | Display | | | | Display | |
+ | | | | | | | |
+ | +------------+ | | +----------+ |
+ +-----------------------------------------------------+ +----------------------------------------------+
+
+````
+
+### Build Steps (these only apply if building locally)
+
+1. Prerequisite before building
+
+ weston, wayland, waltham and gstreamer should be built and available.
+
+2. In waltham-receiver directory, create build directory
+
+ $ meson -Dprefix=$PREFIX_PATH build/
+
+3. Run ninja
+
+ $ ninja -C build/
+
+4. waltham-receiver binary should be availaible in build directory
+
+### Connection Establishment
+
+1. Connect two board over ethernet.
+
+2. Assign IP to both the boards and check if the simple ping works.
+
+ For example:if transmitter IP: 192.168.2.51 and Waltham-Receiver IP:
+ 192.168.2.52 then
+
+ $ping 192.168.2.52 (you can also ping vice versa)
+
+3. Make sure that IP address specified in the weston.ini under
+ [transmitter-output] matches the Waltham-Receiver IP.
+
+4. Make sure that IP address on the transmitter side match the Waltham-Receiver
+ IP.
+
+### Basic test steps with AGL
+
+0. Under AGL platform you should already have the waltham-receiver installed.
+
+1. Start the compositor with the transmitter plugin at the transmitter side,
+ use agl-shell-app-id=app_id of the run the application and put it on
+ transmitter screen. Setup a shared port between transmitter and receiver.
+ Setup the receiver IP address. The transmitter-plugin uses the same section
+ syntax as the remoting plugin.
+
+2. Start the compositor at the receiver side
+
+3. Start the receiver using -p <shared_port> -i <app_id>. If not app_id is
+ specified the app_id passed by the transmitter will be used. Use -i <app_id>
+ if you'd like to have the ability to activate and switch the surface if you
+ intended to start multiple application and still be able to send input and
+ display the received streamed buffers from the transmitter side.
+
+4. Start the application on the transmitter side and watch it appear on the
+ receiver side.
diff --git a/config/receiver_pipeline_example_general.cfg b/config/receiver_pipeline_example_general.cfg
new file mode 100644
index 0000000..be4d562
--- /dev/null
+++ b/config/receiver_pipeline_example_general.cfg
@@ -0,0 +1 @@
+ udpsrc port=YOUR_RECIEVER_PORT caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)JPEG,payload=(int)26" ! rtpjpegdepay ! jpegdec ! waylandsink name=sink sync=true
diff --git a/config/receiver_pipeline_example_intel.cfg b/config/receiver_pipeline_example_intel.cfg
new file mode 100644
index 0000000..3872f28
--- /dev/null
+++ b/config/receiver_pipeline_example_intel.cfg
@@ -0,0 +1 @@
+ udpsrc port=YOUR_RECIEVER_PORT caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264,payload=(int)96" ! rtpjitterbuffer latency=0 ! rtph264depay ! h264parse config-interval=1 disable-passthrough=true ! mfxdecode ! waylandsink name=sink sync=true
diff --git a/config/receiver_pipeline_example_rcar.cfg b/config/receiver_pipeline_example_rcar.cfg
new file mode 100644
index 0000000..15fd4ef
--- /dev/null
+++ b/config/receiver_pipeline_example_rcar.cfg
@@ -0,0 +1 @@
+ udpsrc port=YOUR_RECIEVER_PORT caps="application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=(string)H264,payload=(int)96" ! rtpjitterbuffer latency=0 ! rtph264depay ! h264parse config-interval=1 disable-passthrough=true ! omxh264dec no-reorder=true ! waylandsink name=sink
diff --git a/include/bitmap.h b/include/bitmap.h
new file mode 100644
index 0000000..3cef52d
--- /dev/null
+++ b/include/bitmap.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef IVICONTROLLER_BITMAP_H_
+#define IVICONTROLLER_BITMAP_H_
+
+#include <stdint.h>
+
+int save_as_bitmap(const char *filename,
+ const char *buffer,
+ int32_t image_size,
+ int32_t width,
+ int32_t height,
+ int16_t bpp
+ );
+
+#endif /* IVICONTROLLER_BITMAP_H_*/
diff --git a/include/os-compatibility.h b/include/os-compatibility.h
new file mode 100644
index 0000000..690f229
--- /dev/null
+++ b/include/os-compatibility.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef OS_COMPATIBILITY_H
+#define OS_COMPATIBILITY_H
+
+#include <sys/types.h>
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#else
+static inline int
+backtrace(void **buffer, int size)
+{
+ return 0;
+}
+#endif
+
+int
+os_fd_set_cloexec(int fd);
+
+int
+os_socketpair_cloexec(int domain, int type, int protocol, int *sv);
+
+int
+os_epoll_create_cloexec(void);
+
+int
+os_create_anonymous_file(off_t size);
+
+#ifndef HAVE_STRCHRNUL
+char *
+strchrnul(const char *s, int c);
+#endif
+
+#endif /* OS_COMPATIBILITY_H */
diff --git a/include/wth-receiver-buffer.h b/include/wth-receiver-buffer.h
new file mode 100644
index 0000000..7e01b8c
--- /dev/null
+++ b/include/wth-receiver-buffer.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef WTH_SERVER_WALTHAM_BUFFER_H_
+#define WTH_SERVER_WALTHAM_BUFFER_H_
+
+/* wthp_blob_factory protocol object */
+struct blob_factory {
+ struct wthp_blob_factory *obj;
+ struct client *client;
+ struct wl_list link; /* struct client::blob_factory_list */
+};
+
+/* wthp_buffer protocol object */
+struct buffer {
+ struct wthp_buffer *obj;
+ uint32_t data_sz;
+ void *data;
+ int32_t width;
+ int32_t height;
+ int32_t stride;
+ uint32_t format;
+ struct wl_list link; /* struct client::buffer_list */
+};
+
+void
+client_bind_blob_factory(struct client *c, struct wthp_blob_factory *obj);
+
+#endif
diff --git a/include/wth-receiver-comm.h b/include/wth-receiver-comm.h
new file mode 100644
index 0000000..4499053
--- /dev/null
+++ b/include/wth-receiver-comm.h
@@ -0,0 +1,305 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*******************************************************************************
+** **
+** TARGET : linux **
+** **
+** PROJECT : waltham-receiver **
+** **
+** PURPOSE : Header file declare macros, extern functions, data types etc, **
+** required to interface with waltham IPC library **
+** **
+*******************************************************************************/
+
+#ifndef WTH_SERVER_WALTHAM_COMM_H_
+#define WTH_SERVER_WALTHAM_COMM_H_
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/epoll.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "xdg-shell-client-protocol.h"
+
+#include <wayland-egl.h>
+#include <wayland-client.h>
+
+#include <waltham-server.h>
+#include <waltham-connection.h>
+
+#define DEBUG 1
+
+struct receiver;
+struct client;
+struct window;
+
+/***** macros *******/
+#define MAX_EPOLL_WATCHES 2
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+ const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+
+#define wl_list_last_until_empty(pos, head, member) \
+ while (!wl_list_empty(head) && \
+ (pos = wl_container_of((head)->prev, pos, member), 1))
+
+#ifndef ARRAY_LENGTH
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+#endif
+
+#ifndef pr_fmt
+# define pr_fmt(fmt) fmt
+#endif
+
+#define wth_error(fmt, ...) \
+ ({ fprintf(stderr, pr_fmt(fmt), ## __VA_ARGS__); fflush(stderr); })
+
+
+/****** incline functions *****/
+static inline void *
+zalloc(size_t size)
+{
+ return calloc(1, size);
+}
+
+
+/***** Data types *****/
+/* wthp_region protocol object */
+struct region {
+ struct wthp_region *obj;
+ /* pixman_region32_t region; */
+ struct wl_list link; /* struct client::region_list */
+};
+
+/* wthp_compositor protocol object */
+struct compositor {
+ struct wthp_compositor *obj;
+ struct client *client;
+ struct wl_list link; /* struct client::compositor_list */
+};
+
+/* wthp_surface protocol object */
+struct surface {
+ struct wthp_surface *obj;
+ uint32_t ivi_id;
+ char *ivi_app_id;
+ struct ivisurface *ivisurf;
+ struct wthp_callback *cb;
+ struct window *shm_window;
+ struct wl_list link; /* struct client::surface_list */
+};
+/* wthp_ivi_surface protocol object */
+struct ivisurface {
+ struct wthp_ivi_surface *obj;
+ struct wthp_callback *cb;
+ struct wl_list link; /* struct client::surface_list */
+ struct surface *surf;
+};
+
+/* wthp_ivi_application protocol object */
+struct application {
+ struct wthp_ivi_application *obj;
+ struct client *client;
+ struct wl_list link; /* struct client::surface_list */
+};
+
+struct application_id {
+ struct wthp_ivi_app_id *obj;
+ struct client *client;
+ struct wl_list link; /* struct client::surface_list */
+};
+
+/* wthp_registry protocol object */
+struct registry {
+ struct wthp_registry *obj;
+ struct client *client;
+ struct wl_list link; /* struct client::registry_list */
+};
+
+/* epoll structure */
+struct watch {
+ struct receiver *receiver;
+ int fd;
+ void (*cb)(struct watch *w, uint32_t events);
+};
+
+struct client {
+ struct wl_list link; /* struct receiver::client_list */
+ struct receiver *receiver;
+
+ struct wth_connection *connection;
+ struct watch conn_watch;
+
+ /* client object lists for clean-up on disconnection */
+ struct wl_list registry_list; /* struct registry::link */
+ struct wl_list compositor_list; /* struct compositor::link */
+ struct wl_list region_list; /* struct region::link */
+ struct wl_list surface_list; /* struct surface::link */
+ struct wl_list buffer_list; /* struct buffer::link */
+ struct wl_list seat_list; /* struct seat::link */
+ struct wl_list pointer_list; /* struct pointer::link */
+ struct wl_list touch_list; /* struct touch::link */
+};
+
+/* receiver structure */
+struct receiver {
+ int listen_fd;
+ struct watch listen_watch;
+
+ bool running;
+ int epoll_fd;
+
+ struct wl_list client_list; /* struct client::link */
+};
+
+struct shm_buffer {
+ struct wl_buffer *buffer;
+ void *shm_data;
+ int busy;
+};
+
+struct display {
+ struct wl_display *display;
+ struct wl_registry *registry;
+ struct wl_compositor *compositor;
+ struct wl_shm *shm;
+ bool has_xrgb;
+
+ struct xdg_wm_base *wm_base;
+ struct wl_seat *seat;
+ struct wl_pointer *wl_pointer;
+ struct wl_keyboard *wl_keyboard;
+ struct wl_touch *wl_touch;
+ struct window *window;
+ struct {
+ EGLDisplay dpy;
+ EGLContext ctx;
+ EGLConfig conf;
+
+ PFNEGLCREATEIMAGEKHRPROC create_image;
+ PFNEGLDESTROYIMAGEKHRPROC destroy_image;
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_texture_2d;
+ } egl;
+ struct {
+ GLuint vertex_shader;
+ GLuint fragment_shader;
+ GLuint program_object;
+ GLuint texture;
+ } gl;
+};
+
+struct window {
+ struct display *display;
+ struct {
+ GLuint rotation_uniform;
+ GLuint pos;
+ GLuint col;
+ } gl;
+ int width, height;
+ int x, y;
+ struct wl_surface *surface;
+ struct ivi_surface *ivi_surface;
+
+ struct shm_buffer buffers[2];
+ struct shm_buffer *prev_buffer;
+
+ struct wl_callback *callback;
+ uint32_t window_frames;
+ uint32_t window_benchmark_time;
+ int wait;
+ struct surface *receiver_surf;
+ int frame_sync;
+
+ struct xdg_surface *xdg_surface;
+ struct xdg_toplevel *xdg_toplevel;
+ const char *app_id;
+ bool wait_for_configure;
+ int maximized, fullscreen, opaque;
+
+ struct wl_egl_window *native;
+ EGLSurface egl_surface;
+ EGLImageKHR egl_img;
+ struct seat *receiver_seat;
+ struct pointer *receiver_pointer;
+ bool ready;
+ uint32_t id_ivisurf;
+};
+
+/**
+* receiver_accept_client
+*
+* Accepts new waltham client connection and instantiates client structure
+*
+* @param names struct receiver *srv
+* @param value socket connection info and client data
+* @return none
+*/
+void receiver_accept_client(struct receiver *srv);
+
+/**
+* receiver_flush_clients
+*
+* write all the pending requests from the clients to socket
+*
+* @param names struct receiver *srv
+* @param value socket connection info and client data
+* @return none
+*/
+void receiver_flush_clients(struct receiver *srv);
+
+/**
+* client_destroy
+*
+* Destroy client connection
+*
+* @param names struct client *c
+* @param value client data
+* @return none
+*/
+void client_destroy(struct client *c);
+
+void
+client_post_out_of_memory(struct client *c);
+
+int
+wth_receiver_weston_main(struct window *window, const char *app_id, int port);
+
+
+#endif
diff --git a/include/wth-receiver-seat.h b/include/wth-receiver-seat.h
new file mode 100644
index 0000000..ed01109
--- /dev/null
+++ b/include/wth-receiver-seat.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WTH_SERVER_WALTHAM_SEAT_H_
+#define WTH_SERVER_WALTHAM_SEAT_H_
+
+struct pointer;
+struct touch;
+struct window;
+struct receiver;
+struct client;
+
+struct wthp_seat;
+
+enum wthp_seat_capability {
+ /**
+ * the seat has pointer devices
+ */
+ WTHP_SEAT_CAPABILITY_POINTER = 1,
+ /**
+ * the seat has one or more keyboards
+ */
+ WTHP_SEAT_CAPABILITY_KEYBOARD = 2,
+ /**
+ * the seat has touch devices
+ */
+ WTHP_SEAT_CAPABILITY_TOUCH = 4,
+};
+
+
+/* wthp_seat protocol object */
+struct seat {
+ struct wthp_seat *obj;
+ struct client *client;
+ struct pointer *pointer;
+ struct keyboard *keyboard;
+ struct touch *touch;
+ struct wl_list link; /* struct client::seat_list */
+};
+
+/* wthp_pointer protocol object */
+struct pointer {
+ struct wthp_pointer *obj;
+ struct seat *seat;
+ struct wl_list link; /* struct client::pointer_list */
+};
+
+/* wthp_keyboard protocol object */
+struct keyboard {
+ struct wthp_keyboard *obj;
+ struct seat *seat;
+ struct wl_list link; /* struct client::keyboard_list */
+};
+
+/* wthp_touch protocol object */
+struct touch {
+ struct wthp_touch *obj;
+ struct seat *seat;
+ struct wl_list link; /* struct client::touch_list */
+};
+
+
+/**
+* waltham_pointer_enter
+*
+* Send pointer enter event received from weston to waltham client
+*
+* @param names struct window *window
+* uint32_t serial
+* wl_fixed_t sx
+* wl_fixed_t sy
+* @param value window - window information
+* serial - serial number of the enter event
+* sx - surface-local x coordinate
+* sy - surface-local y coordinate
+* @return none
+*/
+void waltham_pointer_enter(struct window *window, uint32_t serial,
+ wl_fixed_t sx, wl_fixed_t sy);
+
+/**
+* waltham_pointer_leave
+*
+* Send pointer leave event received from weston to waltham client
+*
+* @param names struct window *window
+* uint32_t serial
+* @param value window - window information
+* serial - serial number of the leave event
+* @return none
+*/
+void waltham_pointer_leave(struct window *window, uint32_t serial);
+
+/**
+* waltham_pointer_motion
+*
+* Send pointer motion event received from weston to waltham client
+*
+* @param names struct window *window
+* uint32_t time
+* wl_fixed_t sx
+* wl_fixed_t sy
+* @param value window - window information
+* time - timestamp with millisecond granularity
+* sx - surface-local x coordinate
+* sy - surface-local y coordinate
+* @return none
+*/
+void waltham_pointer_motion(struct window *window, uint32_t time,
+ wl_fixed_t sx, wl_fixed_t sy);
+
+/**
+* waltham_pointer_button
+*
+* Send pointer button event received from weston to waltham client
+*
+* @param names struct window *window
+* uint32_t serial
+* uint32_t time
+* uint32_t button
+* uint32_t state
+* @param value window - window information
+* serial - serial number of the button event
+* time - timestamp with millisecond granularity
+* button - button that produced the event
+* state - physical state of the button
+* @return none
+*/
+void waltham_pointer_button(struct window *window, uint32_t serial,
+ uint32_t time, uint32_t button,
+ uint32_t state);
+
+/**
+* waltham_pointer_axis
+*
+* Send pointer axis event received from weston to waltham client
+*
+* @param names struct window *window
+* uint32_t time
+* uint32_t axis
+* wl_fixed_t value
+* @param value window - window information
+* time - timestamp with millisecond granularity
+* axis - axis type
+* value - length of vector in surface-local coordinate space
+* @return none
+*/
+void waltham_pointer_axis(struct window *window, uint32_t time,
+ uint32_t axis, wl_fixed_t value);
+
+/**
+* waltham_touch_down
+*
+* Send touch down event received from weston to waltham client
+*
+* @param names struct window *window
+* uint32_t serial
+* uint32_t time
+* int32_t id
+* wl_fixed_t x_w
+* wl_fixed_t y_w
+* @param value window - window information
+* serial - serial number of the touch down event
+* time - timestamp with millisecond granularity
+* id - the unique ID of this touch point
+* x_w - surface-local x coordinate
+* y_w - surface-local y coordinate
+* @return none
+*/
+void waltham_touch_down(struct window *window, uint32_t serial,
+ uint32_t time, int32_t id,
+ wl_fixed_t x_w, wl_fixed_t y_w);
+
+/**
+* waltham_touch_up
+*
+* Send touch up event received from weston to waltham client
+*
+* @param names struct window *window
+* uint32_t serial
+* uint32_t time
+* int32_t id
+* @param value window - window information
+* serial - serial number of the touch up event
+* time - timestamp with millisecond granularity
+* id - the unique ID of this touch point
+* @return none
+*/
+void waltham_touch_up(struct window *window, uint32_t serial,
+ uint32_t time, int32_t id);
+
+/**
+* waltham_touch_motion
+*
+* Send touch motion event received from weston to waltham client
+*
+* @param names struct window *window
+* uint32_t time
+* int32_t id
+* wl_fixed_t x_w
+* wl_fixed_t y_w
+* @param value window - window information
+* time - timestamp with millisecond granularity
+* id - the unique ID of this touch point
+* x_w - surface-local x coordinate
+* y_w - surface-local y coordinate
+* @return none
+*/
+void waltham_touch_motion(struct window *window, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w);
+
+/**
+* waltham_touch_frame
+*
+* Send touch frame event received from weston to waltham client
+*
+* @param names struct window *window
+* @param value window - window information
+* @return none
+*/
+void waltham_touch_frame(struct window *window);
+
+/**
+* waltham_touch_cancel
+*
+* Send touch cancel event received from weston to waltham client
+*
+* @param names struct window *window
+* @param value window - window information
+* @return none
+*/
+void waltham_touch_cancel(struct window *window);
+
+void
+client_bind_seat(struct client *c, struct wthp_seat *obj);
+
+void
+seat_send_updated_caps(struct seat *seat);
+
+#endif
diff --git a/include/wth-receiver-surface.h b/include/wth-receiver-surface.h
new file mode 100644
index 0000000..cbcf208
--- /dev/null
+++ b/include/wth-receiver-surface.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef WTH_SERVER_WALTHAM_SURFACE_H_
+#define WTH_SERVER_WALTHAM_SURFACE_H_
+
+struct client;
+struct compositor;
+
+void
+region_destroy(struct region *region);
+
+void
+compositor_destroy(struct compositor *comp);
+
+void
+surface_destroy(struct surface *surface);
+
+void
+client_bind_compositor(struct client *c, struct wthp_compositor *obj);
+
+#endif
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..4443a85
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,149 @@
+project('waltham-receiver',
+ 'c',
+ version: '0.0.1',
+ default_options: [
+ 'warning_level=3',
+ 'c_std=gnu99',
+ ],
+ meson_version: '>= 0.50',
+ license: 'MIT/Expat',
+)
+
+pkgconfig = import('pkgconfig')
+cc = meson.get_compiler('c')
+
+add_project_arguments(
+ cc.get_supported_arguments([
+ '-Wno-unused-parameter',
+ '-Wno-pedantic',
+ '-Wextra',
+ '-Werror'
+ ]),
+ language: 'c'
+)
+
+add_project_arguments([
+ '-DPACKAGE_STRING="waltham-receiver @0@"'.format(meson.project_version()),
+ '-D_GNU_SOURCE',
+ '-D_ALL_SOURCE',
+ ],
+ language: 'c'
+)
+
+optional_libc_funcs = [ 'memfd_create', 'strchrnul' ]
+foreach func: optional_libc_funcs
+ if cc.has_function(func)
+ add_project_arguments('-DHAVE_@0@=1'.format(func.to_upper()), language: 'c')
+ endif
+endforeach
+
+env_modmap = ''
+
+libwayland_dep = dependency('wayland-client')
+libwayland_cursor_dep = dependency('wayland-cursor')
+libwaltham_dep = dependency('waltham')
+
+dep_scanner = dependency('wayland-scanner', native: true)
+prog_scanner = find_program(dep_scanner.get_pkgconfig_variable('wayland_scanner'))
+dep_wp = dependency('wayland-protocols', version: '>= 1.18')
+dir_wp_base = dep_wp.get_pkgconfig_variable('pkgdatadir')
+xdg_shell_xml = join_paths(dir_wp_base, 'stable', 'xdg-shell', 'xdg-shell.xml')
+
+protocols = [
+ { 'name': 'xdg-shell', 'source': 'wp-stable' },
+]
+
+foreach proto: protocols
+ proto_name = proto['name']
+ if proto['source'] == 'internal'
+ base_file = proto_name
+ xml_path = join_paths('protocol', '@0@.xml'.format(base_file))
+ elif proto['source'] == 'wp-stable'
+ base_file = proto_name
+ xml_path = join_paths(dir_wp_base, 'stable', proto_name, '@0@.xml'.format(base_file))
+ else
+ base_file = '@0@-unstable-@1@'.format(proto_name, proto['version'])
+ xml_path = join_paths(dir_wp_base, 'unstable', proto_name, '@0@.xml'.format(base_file))
+ endif
+
+ foreach output_type: [ 'client-header', 'server-header', 'private-code' ]
+ if output_type == 'client-header'
+ output_file = '@0@-client-protocol.h'.format(base_file)
+ elif output_type == 'server-header'
+ output_file = '@0@-server-protocol.h'.format(base_file)
+ else
+ output_file = '@0@-protocol.c'.format(base_file)
+ if dep_scanner.version().version_compare('< 1.14.91')
+ output_type = 'code'
+ endif
+ endif
+
+ var_name = output_file.underscorify()
+ target = custom_target(
+ '@0@ @1@'.format(base_file, output_type),
+ command: [ prog_scanner, output_type, '@INPUT@', '@OUTPUT@' ],
+ input: xml_path,
+ output: output_file,
+ )
+
+ set_variable(var_name, target)
+ endforeach
+endforeach
+
+
+dep_gstreamer = dependency('gstreamer-1.0')
+dep_gstreamer_plugins_base = dependency('gstreamer-plugins-base-1.0')
+dep_gstreamer_plugins_bad = dependency('gstreamer-plugins-bad-1.0')
+dep_gstreamer_app = dependency('gstreamer-app-1.0')
+dep_gstreamer_video = dependency('gstreamer-video-1.0')
+dep_gstreamer_alloc = dependency('gstreamer-allocators-1.0')
+dep_egl = dependency('egl')
+dep_gles = dependency('glesv2')
+dep_wayland_egl = dependency('wayland-egl')
+
+prefix_path = get_option('prefix')
+binplugin_dir = join_paths(prefix_path, get_option('bindir'))
+common_inc = include_directories('include')
+
+deps_waltham_receiver = [
+ libwayland_dep, libwayland_cursor_dep,
+ libwaltham_dep,
+ dep_gstreamer, dep_gstreamer_app, dep_gstreamer_plugins_base,
+ dep_gstreamer_plugins_bad,
+ dep_gstreamer_video, dep_gstreamer_alloc,
+ dep_egl, dep_gles, dep_wayland_egl,
+ # gstwayland-1.0 is special here because gstreamer-plugins-bad-1.0 does not
+ # provide it
+ cc.find_library('pthread'), cc.find_library('gstwayland-1.0')
+]
+
+buf_type = get_option('buffer-type')
+buf_type_src = []
+
+if buf_type == 'egl'
+ buf_type_src += 'src/wth-receiver-gst-egl.c'
+elif buf_type == 'shm'
+ buf_type_src += 'src/wth-receiver-gst-shm.c'
+endif
+
+srcs_wth_receiver = [
+ 'src/bitmap.c',
+ 'src/os-compatibility.c',
+ 'src/wth-receiver-comm.c',
+ 'src/wth-receiver-buffer.c',
+ 'src/wth-receiver-surface.c',
+ 'src/wth-receiver-seat.c',
+ 'src/wth-receiver-main.c',
+ buf_type_src,
+ xdg_shell_client_protocol_h,
+ xdg_shell_protocol_c,
+]
+
+exe_wth_receiver = executable(
+ 'waltham-receiver',
+ srcs_wth_receiver,
+ include_directories: common_inc,
+ dependencies: deps_waltham_receiver,
+ install_rpath: binplugin_dir,
+ install: true
+)
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..30a6f0f
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,7 @@
+option(
+ 'buffer-type',
+ type: 'combo',
+ choices: [ 'auto', 'egl', 'shm' ],
+ value: 'shm',
+ description: 'Default buffer type to use'
+)
diff --git a/src/bitmap.c b/src/bitmap.c
new file mode 100644
index 0000000..2c7fdb5
--- /dev/null
+++ b/src/bitmap.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "bitmap.h"
+#include <stdio.h>
+
+struct __attribute__ ((__packed__)) BITMAPFILEHEADER {
+ char bfType[2];
+ uint32_t bfSize;
+ uint16_t bfReserved1;
+ uint16_t bfReserved2;
+ uint32_t bfOffBits;
+};
+
+struct __attribute__ ((__packed__)) BITMAPINFOHEADER {
+ uint32_t biSize;
+ uint32_t biWidth;
+ uint32_t biHeight;
+ uint16_t biPlanes;
+ uint16_t biBitCount;
+ uint32_t biCompression;
+ uint32_t biSizeImage;
+ uint32_t biXPixPerMeter;
+ uint32_t biYPixPerMeter;
+ uint32_t biClrUsed;
+ uint32_t biClrImporant;
+};
+
+static void
+create_file_header(struct BITMAPFILEHEADER *file_header, int32_t image_size)
+{
+ file_header->bfType[0] = 'B';
+ file_header->bfType[1] = 'M';
+ file_header->bfSize = sizeof(struct BITMAPFILEHEADER)
+ + sizeof(struct BITMAPINFOHEADER)
+ + image_size;
+ file_header->bfOffBits = sizeof(struct BITMAPFILEHEADER)
+ + sizeof(struct BITMAPINFOHEADER);
+}
+
+static void
+create_info_header(struct BITMAPINFOHEADER *info_header, int32_t image_size, int32_t width, int32_t height, int16_t bpp)
+{
+ info_header->biSize = sizeof(struct BITMAPINFOHEADER);
+ info_header->biWidth = width;
+ info_header->biHeight = height;
+ info_header->biPlanes = 1;
+ info_header->biBitCount = bpp;
+ info_header->biSizeImage = image_size;
+}
+
+static int
+write_bitmap(const char *filename,
+ const struct BITMAPFILEHEADER *file_header,
+ const struct BITMAPINFOHEADER *info_header,
+ const char *buffer)
+{
+ FILE *fp = fopen(filename, "w");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ fwrite(file_header, sizeof(struct BITMAPFILEHEADER), 1, fp);
+ fwrite(info_header, sizeof(struct BITMAPINFOHEADER), 1, fp);
+ fwrite(buffer, info_header->biSizeImage, 1, fp);
+
+ fclose(fp);
+ return 0;
+}
+
+int
+save_as_bitmap(const char *filename,
+ const char *buffer,
+ int32_t image_size,
+ int32_t width,
+ int32_t height,
+ int16_t bpp)
+{
+ if ((filename == NULL) || (buffer == NULL)) {
+ return -1;
+ }
+
+ struct BITMAPFILEHEADER file_header = {};
+ struct BITMAPINFOHEADER info_header = {};
+
+ create_file_header(&file_header, image_size);
+ create_info_header(&info_header, image_size, width, height, bpp);
+ return write_bitmap(filename, &file_header, &info_header, buffer);
+}
diff --git a/src/os-compatibility.c b/src/os-compatibility.c
new file mode 100644
index 0000000..d9502e5
--- /dev/null
+++ b/src/os-compatibility.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "os-compatibility.h"
+
+int
+os_fd_set_cloexec(int fd)
+{
+ long flags;
+
+ if (fd == -1)
+ return -1;
+
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1)
+ return -1;
+
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+set_cloexec_or_close(int fd)
+{
+ if (os_fd_set_cloexec(fd) != 0) {
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+int
+os_socketpair_cloexec(int domain, int type, int protocol, int *sv)
+{
+ int ret;
+
+#ifdef SOCK_CLOEXEC
+ ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
+ if (ret == 0 || errno != EINVAL)
+ return ret;
+#endif
+
+ ret = socketpair(domain, type, protocol, sv);
+ if (ret < 0)
+ return ret;
+
+ sv[0] = set_cloexec_or_close(sv[0]);
+ sv[1] = set_cloexec_or_close(sv[1]);
+
+ if (sv[0] != -1 && sv[1] != -1)
+ return 0;
+
+ close(sv[0]);
+ close(sv[1]);
+ return -1;
+}
+
+int
+os_epoll_create_cloexec(void)
+{
+ int fd;
+
+#ifdef EPOLL_CLOEXEC
+ fd = epoll_create1(EPOLL_CLOEXEC);
+ if (fd >= 0)
+ return fd;
+ if (errno != EINVAL)
+ return -1;
+#endif
+
+ fd = epoll_create(1);
+ return set_cloexec_or_close(fd);
+}
+
+static int
+create_tmpfile_cloexec(char *tmpname)
+{
+ int fd;
+
+#ifdef HAVE_MKOSTEMP
+ fd = mkostemp(tmpname, O_CLOEXEC);
+ if (fd >= 0)
+ unlink(tmpname);
+#else
+ fd = mkstemp(tmpname);
+ if (fd >= 0) {
+ fd = set_cloexec_or_close(fd);
+ unlink(tmpname);
+ }
+#endif
+
+ return fd;
+}
+
+/*
+ * Create a new, unique, anonymous file of the given size, and
+ * return the file descriptor for it. The file descriptor is set
+ * CLOEXEC. The file is immediately suitable for mmap()'ing
+ * the given size at offset zero.
+ *
+ * The file should not have a permanent backing store like a disk,
+ * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
+ *
+ * The file name is deleted from the file system.
+ *
+ * The file is suitable for buffer sharing between processes by
+ * transmitting the file descriptor over Unix sockets using the
+ * SCM_RIGHTS methods.
+ *
+ * If the C library implements posix_fallocate(), it is used to
+ * guarantee that disk space is available for the file at the
+ * given size. If disk space is insufficent, errno is set to ENOSPC.
+ * If posix_fallocate() is not supported, program may receive
+ * SIGBUS on accessing mmap()'ed file contents instead.
+ */
+int
+os_create_anonymous_file(off_t size)
+{
+ static const char template[] = "/weston-shared-XXXXXX";
+ const char *path;
+ char *name;
+ int fd;
+ int ret;
+
+ path = getenv("XDG_RUNTIME_DIR");
+ if (!path) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ name = malloc(strlen(path) + sizeof(template));
+ if (!name)
+ return -1;
+
+ strcpy(name, path);
+ strcat(name, template);
+
+ fd = create_tmpfile_cloexec(name);
+
+ free(name);
+
+ if (fd < 0)
+ return -1;
+
+#ifdef HAVE_POSIX_FALLOCATE
+ ret = posix_fallocate(fd, 0, size);
+ if (ret != 0) {
+ close(fd);
+ errno = ret;
+ return -1;
+ }
+#else
+ ret = ftruncate(fd, size);
+ if (ret < 0) {
+ close(fd);
+ return -1;
+ }
+#endif
+
+ return fd;
+}
+
+#ifndef HAVE_STRCHRNUL
+char *
+strchrnul(const char *s, int c)
+{
+ while (*s && *s != c)
+ s++;
+ return (char *)s;
+}
+#endif
diff --git a/src/wth-receiver-buffer.c b/src/wth-receiver-buffer.c
new file mode 100644
index 0000000..accf0cd
--- /dev/null
+++ b/src/wth-receiver-buffer.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wth-receiver-comm.h"
+#include "wth-receiver-buffer.h"
+
+static void
+buffer_handle_destroy(struct wthp_buffer *wthp_buffer)
+{
+ struct buffer *buf = wth_object_get_user_data((struct wth_object *)wthp_buffer);
+
+ wthp_buffer_free(wthp_buffer);
+ wl_list_remove(&buf->link);
+ free(buf);
+}
+
+static const struct wthp_buffer_interface buffer_implementation = {
+ buffer_handle_destroy
+};
+
+/* BEGIN wthp_blob_factory implementation */
+
+static void
+blob_factory_create_buffer(struct wthp_blob_factory *blob_factory,
+ struct wthp_buffer *wthp_buffer, uint32_t data_sz, void *data,
+ int32_t width, int32_t height, int32_t stride, uint32_t format)
+{
+ struct blob_factory *blob = wth_object_get_user_data((struct wth_object *)blob_factory);
+ struct buffer *buffer;
+
+ buffer = zalloc(sizeof *buffer);
+ if (!buffer) {
+ client_post_out_of_memory(blob->client);
+ return;
+ }
+
+ wl_list_insert(&blob->client->buffer_list, &buffer->link);
+
+ buffer->data_sz = data_sz;
+ buffer->data = data;
+ buffer->width = width;
+ buffer->height = height;
+ buffer->stride = stride;
+ buffer->format = format;
+ buffer->obj = wthp_buffer;
+
+ wthp_buffer_set_interface(wthp_buffer, &buffer_implementation, buffer);
+}
+
+static const struct wthp_blob_factory_interface blob_factory_implementation = {
+ blob_factory_create_buffer
+};
+
+void
+client_bind_blob_factory(struct client *c, struct wthp_blob_factory *obj)
+{
+ struct blob_factory *blob;
+
+ blob = zalloc(sizeof *blob);
+ if (!blob) {
+ client_post_out_of_memory(c);
+ return;
+ }
+
+ blob->obj = obj;
+ blob->client = c;
+ wl_list_insert(&c->compositor_list, &blob->link);
+
+ wthp_blob_factory_set_interface(obj,
+ &blob_factory_implementation, blob);
+ fprintf(stderr, "client %p bound wthp_blob_factory\n", c);
+}
diff --git a/src/wth-receiver-comm.c b/src/wth-receiver-comm.c
new file mode 100644
index 0000000..e6c0266
--- /dev/null
+++ b/src/wth-receiver-comm.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*******************************************************************************
+** **
+** TARGET : linux **
+** **
+** PROJECT : waltham-receiver **
+** **
+** PURPOSE : This file acts as interface to waltham IPC library **
+** **
+** **
+*******************************************************************************/
+
+#include "wth-receiver-comm.h"
+#include "wth-receiver-surface.h"
+#include "wth-receiver-seat.h"
+#include "wth-receiver-buffer.h"
+
+extern uint16_t tcp_port;
+extern const char *my_app_id;
+
+void
+client_post_out_of_memory(struct client *c)
+{
+ struct wth_display *disp;
+
+ disp = wth_connection_get_display(c->connection);
+ wth_object_post_error((struct wth_object *) disp, 1, "out of memory");
+}
+
+/*
+ * waltam ivi surface implementation
+ */
+static void
+wthp_ivi_surface_destroy(struct wthp_ivi_surface * ivi_surface)
+{
+ struct ivisurface *ivisurf = wth_object_get_user_data((struct wth_object *)ivi_surface);
+
+ if (ivisurf->surf->ivi_app_id)
+ free(ivisurf->surf->ivi_app_id);
+
+ free(ivisurf);
+}
+
+static const struct wthp_ivi_surface_interface wthp_ivi_surface_implementation = {
+ wthp_ivi_surface_destroy,
+};
+
+
+/**
+ * app_id version
+ */
+static void
+wthp_ivi_app_id_surface_create(struct wthp_ivi_app_id *ivi_application,
+ const char *app_id,
+ struct wthp_surface * wthp_surface,
+ struct wthp_ivi_surface *obj)
+{
+ struct surface *surface = wth_object_get_user_data((struct wth_object *)wthp_surface);
+
+ /* we destroy it wthp_ivi_surface_implementation:: */
+ if (my_app_id) {
+ surface->ivi_app_id = strdup(my_app_id);
+ surface->shm_window->app_id = surface->ivi_app_id;
+ }
+
+ struct ivisurface *ivisurf;
+
+ ivisurf = zalloc(sizeof *ivisurf);
+ if (!ivisurf) {
+ return;
+ }
+
+ ivisurf->obj = obj;
+ ivisurf->surf = surface;
+
+ wthp_ivi_surface_set_interface(obj,
+ &wthp_ivi_surface_implementation, ivisurf);
+
+ if (my_app_id)
+ wth_receiver_weston_main(surface->shm_window, my_app_id, tcp_port);
+ else
+ wth_receiver_weston_main(surface->shm_window, app_id, tcp_port);
+
+ while (!surface->shm_window->ready)
+ usleep(1);
+}
+
+static const struct wthp_ivi_app_id_interface wthp_ivi_app_id_implementation = {
+ wthp_ivi_app_id_surface_create,
+};
+
+static void
+client_bind_wthp_ivi_app_id(struct client *c, struct wthp_ivi_app_id *obj)
+{
+ struct application_id *app;
+
+ app = zalloc(sizeof *app);
+ if (!app) {
+ client_post_out_of_memory(c);
+ return;
+ }
+
+ app->obj = obj;
+ app->client = c;
+ wl_list_insert(&c->compositor_list, &app->link);
+
+ wthp_ivi_app_id_set_interface(obj, &wthp_ivi_app_id_implementation, app);
+}
+
+/*
+ * waltham registry implementation
+ */
+static void
+registry_destroy(struct registry *reg)
+{
+ wthp_registry_free(reg->obj);
+ wl_list_remove(&reg->link);
+ free(reg);
+}
+
+static void
+registry_handle_destroy(struct wthp_registry *registry)
+{
+ struct registry *reg = wth_object_get_user_data((struct wth_object *)registry);
+ registry_destroy(reg);
+}
+
+static void
+registry_handle_bind(struct wthp_registry *registry,
+ uint32_t name, struct wth_object *id,
+ const char *interface, uint32_t version)
+{
+
+ struct registry *reg = wth_object_get_user_data((struct wth_object *)registry);
+
+ if (strcmp(interface, "wthp_compositor") == 0) {
+ client_bind_compositor(reg->client, (struct wthp_compositor *)id);
+ } else if (strcmp(interface, "wthp_blob_factory") == 0) {
+ struct client *client = reg->client;
+ struct seat *seat, *tmp, *get_seat;
+
+ client_bind_blob_factory(reg->client, (struct wthp_blob_factory *)id);
+
+ get_seat = NULL;
+ wl_list_for_each_safe(seat, tmp, &client->seat_list, link) {
+ get_seat = seat;
+ }
+
+ if (get_seat)
+ seat_send_updated_caps(get_seat);
+ } else if (strcmp(interface, "wthp_ivi_app_id") == 0) {
+ client_bind_wthp_ivi_app_id(reg->client, (struct wthp_ivi_app_id *) id);
+ } else if (strcmp(interface, "wthp_seat") == 0) {
+ client_bind_seat(reg->client, (struct wthp_seat *)id);
+ } else {
+ wth_object_post_error((struct wth_object *)registry, 0,
+ "%s: unknown name %u", __func__, name);
+ wth_object_delete(id);
+ }
+}
+
+static const struct wthp_registry_interface registry_implementation = {
+ registry_handle_destroy,
+ registry_handle_bind
+};
+
+/*
+ * waltham display implementation
+ */
+
+static void
+display_handle_client_version(struct wth_display *wth_display,
+ uint32_t client_version)
+{
+ wth_object_post_error((struct wth_object *)wth_display, 0,
+ "unimplemented: %s", __func__);
+}
+
+static void
+display_handle_sync(struct wth_display * wth_display, struct wthp_callback * callback)
+{
+ wthp_callback_send_done(callback, 0);
+ wthp_callback_free(callback);
+}
+
+static void
+display_handle_get_registry(struct wth_display *wth_display,
+ struct wthp_registry *registry)
+{
+ struct client *c = wth_object_get_user_data((struct wth_object *)wth_display);
+ struct registry *reg;
+
+ reg = zalloc(sizeof *reg);
+ if (!reg) {
+ client_post_out_of_memory(c);
+ return;
+ }
+
+ reg->obj = registry;
+ reg->client = c;
+ wl_list_insert(&c->registry_list, &reg->link);
+ wthp_registry_set_interface(registry,
+ &registry_implementation, reg);
+
+ wthp_registry_send_global(registry, 1, "wthp_compositor", 4);
+ wthp_registry_send_global(registry, 1, "wthp_ivi_app_id", 1);
+ wthp_registry_send_global(registry, 1, "wthp_seat", 4);
+ wthp_registry_send_global(registry, 1, "wthp_blob_factory", 4);
+
+}
+
+const struct wth_display_interface display_implementation = {
+ display_handle_client_version,
+ display_handle_sync,
+ display_handle_get_registry
+};
+
+/*
+ * utility functions
+ */
+static int
+watch_ctl(struct watch *w, int op, uint32_t events)
+{
+ struct epoll_event ee;
+
+ ee.events = events;
+ ee.data.ptr = w;
+ return epoll_ctl(w->receiver->epoll_fd, op, w->fd, &ee);
+}
+
+/**
+* client_destroy
+*
+* Destroy client connection
+*
+* @param names struct client *c
+* @param value client data
+* @return none
+*/
+void
+client_destroy(struct client *c)
+{
+ struct region *region;
+ struct compositor *comp;
+ struct registry *reg;
+ struct surface *surface;
+
+ /* clean up remaining client resources in case the client
+ * did not.
+ */
+ wl_list_last_until_empty(region, &c->region_list, link)
+ region_destroy(region);
+
+ wl_list_last_until_empty(comp, &c->compositor_list, link)
+ compositor_destroy(comp);
+
+ wl_list_last_until_empty(reg, &c->registry_list, link)
+ registry_destroy(reg);
+
+ wl_list_last_until_empty(surface, &c->surface_list, link)
+ surface_destroy(surface);
+
+ wl_list_remove(&c->link);
+ watch_ctl(&c->conn_watch, EPOLL_CTL_DEL, 0);
+ wth_connection_destroy(c->connection);
+ free(c);
+}
+
+/*
+ * functions to handle waltham client connections
+ */
+static void
+connection_handle_data(struct watch *w, uint32_t events)
+{
+
+ struct client *c = container_of(w, struct client, conn_watch);
+ int ret;
+
+ if (events & EPOLLERR) {
+ wth_error("Client %p errored out.\n", c);
+ client_destroy(c);
+ return;
+ }
+
+ if (events & EPOLLHUP) {
+ wth_error("Client %p hung up.\n", c);
+ client_destroy(c);
+ return;
+ }
+
+ if (events & EPOLLOUT) {
+ ret = wth_connection_flush(c->connection);
+ if (ret == 0) {
+ watch_ctl(&c->conn_watch, EPOLL_CTL_MOD, EPOLLIN);
+ } else if (ret < 0 && errno != EAGAIN) {
+ wth_error("Client %p flush error.\n", c);
+ client_destroy(c);
+ return;
+ }
+ }
+
+ if (events & EPOLLIN) {
+ ret = wth_connection_read(c->connection);
+ if (ret < 0) {
+ wth_error("Client %p read error.\n", c);
+ client_destroy(c);
+ return;
+ }
+
+ ret = wth_connection_dispatch(c->connection);
+ if (ret < 0 && errno != EPROTO) {
+ wth_error("Client %p dispatch error.\n", c);
+ client_destroy(c);
+ return;
+ }
+ }
+}
+
+/**
+ * client_create
+ *
+ * Create new client connection
+ *
+ * @param srv receiver structure
+ * @param wth_connection Waltham connection handle
+ * @return Pointer to client structure
+ */
+static struct client *
+client_create(struct receiver *srv, struct wth_connection *conn)
+{
+
+ struct client *c;
+ struct wth_display *disp;
+
+ c = zalloc(sizeof *c);
+ if (!c)
+ return NULL;
+
+ c->receiver = srv;
+ c->connection = conn;
+
+ c->conn_watch.receiver = srv;
+ c->conn_watch.fd = wth_connection_get_fd(conn);
+ c->conn_watch.cb = connection_handle_data;
+ if (watch_ctl(&c->conn_watch, EPOLL_CTL_ADD, EPOLLIN) < 0) {
+ free(c);
+ return NULL;
+ }
+
+
+ wl_list_insert(&srv->client_list, &c->link);
+
+ wl_list_init(&c->registry_list);
+ wl_list_init(&c->compositor_list);
+ wl_list_init(&c->seat_list);
+ wl_list_init(&c->pointer_list);
+ wl_list_init(&c->touch_list);
+ wl_list_init(&c->region_list);
+ wl_list_init(&c->surface_list);
+ wl_list_init(&c->buffer_list);
+
+ disp = wth_connection_get_display(c->connection);
+ wth_display_set_interface(disp, &display_implementation, c);
+
+ return c;
+}
+
+
+/**
+* receiver_flush_clients
+*
+* write all the pending requests from the clients to socket
+*
+* @param names struct receiver *srv
+* @param value socket connection info and client data
+* @return none
+*/
+void
+receiver_flush_clients(struct receiver *srv)
+{
+ struct client *c, *tmp;
+ int ret;
+
+ wl_list_for_each_safe(c, tmp, &srv->client_list, link) {
+ /* Flush out buffered requests. If the Waltham socket is
+ * full, poll it for writable too.
+ */
+ ret = wth_connection_flush(c->connection);
+ if (ret < 0 && errno == EAGAIN) {
+ watch_ctl(&c->conn_watch, EPOLL_CTL_MOD, EPOLLIN | EPOLLOUT);
+ } else if (ret < 0) {
+ perror("Connection flush failed");
+ client_destroy(c);
+ return;
+ }
+ }
+}
+
+/**
+* receiver_accept_client
+*
+* Accepts new waltham client connection and instantiates client structure
+*
+* @param names struct receiver *srv
+* @param value socket connection info and client data
+* @return none
+*/
+void
+receiver_accept_client(struct receiver *srv)
+{
+ struct client *client;
+ struct wth_connection *conn;
+ struct sockaddr_in addr;
+ socklen_t len;
+
+ len = sizeof(addr);
+ conn = wth_accept(srv->listen_fd, (struct sockaddr *)&addr, &len);
+ if (!conn) {
+ wth_error("Failed to accept a connection.\n");
+ return;
+ }
+
+ client = client_create(srv, conn);
+ if (!client) {
+ wth_error("Failed client_create().\n");
+ return;
+ }
+}
diff --git a/src/wth-receiver-gst-egl.c b/src/wth-receiver-gst-egl.c
new file mode 100644
index 0000000..0704e6b
--- /dev/null
+++ b/src/wth-receiver-gst-egl.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*******************************************************************************
+ ** **
+ ** TARGET : linux **
+ ** **
+ ** PROJECT : waltham-receiver **
+ ** **
+ ** PURPOSE : This file is acts as interface to weston compositor at receiver **
+ ** side **
+ ** **
+ *******************************************************************************/
+
+#define GST_USE_UNSTABLE_API
+
+#include <sys/mman.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <gst/gst.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/allocators/gstdmabuf.h>
+#include <gst/app/gstappsink.h>
+#include <pthread.h>
+#include <gst/wayland/wayland.h>
+#include <gst/video/videooverlay.h>
+
+#include <GL/gl.h>
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "xdg-shell-client-protocol.h"
+
+#include "wth-receiver-seat.h"
+#include "wth-receiver-comm.h"
+#include "os-compatibility.h"
+#include "bitmap.h"
+
+#define WINDOW_WIDTH_SIZE 800
+#define WINDOW_HEIGHT_SIZE 600
+
+#define PIPELINE_SIZE 4096
+
+static int running = 1;
+
+typedef struct _GstAppContext {
+ GMainLoop *loop;
+ GstBus *bus;
+
+ GstElement *pipeline;
+ GstElement *sink;
+
+ GstWaylandVideo *wl_video;
+ GstVideoOverlay *overlay;
+
+ struct display *display;
+ struct window *window;
+ GstVideoInfo info;
+
+} GstAppContext;
+
+static const gchar *vertex_shader_str =
+"attribute vec4 a_position; \n"
+"attribute vec2 a_texCoord; \n"
+"varying vec2 v_texCoord; \n"
+"void main() \n"
+"{ \n"
+" gl_Position = a_position; \n"
+" v_texCoord = a_texCoord; \n"
+"} \n";
+
+static const gchar *fragment_shader_str =
+"#ifdef GL_ES \n"
+"precision mediump float; \n"
+"#endif \n"
+"varying vec2 v_texCoord; \n"
+"uniform sampler2D tex; \n"
+"void main() \n"
+"{ \n"
+"vec2 uv; \n"
+"uv = v_texCoord.xy; \n"
+"vec4 c = texture2D(tex, uv); \n"
+"gl_FragColor = c; \n"
+"} \n";
+
+/*
+ * pointer callbcak functions
+ */
+static void
+pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, struct wl_surface *wl_surface,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_enter(window, serial, sx, sy);
+}
+
+static void
+pointer_handle_leave(void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_leave(window, serial);
+
+}
+
+static void
+pointer_handle_motion(void *data, struct wl_pointer *pointer,
+ uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_motion(window, time, sx, sy);
+}
+
+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 display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_button(window, serial, time, button, state);
+}
+
+static void
+pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_axis(window, time, axis, value);
+}
+
+static void
+pointer_handle_frame(void *data, struct wl_pointer *pointer)
+{
+ (void) data;
+ (void) pointer;
+}
+
+static void
+pointer_handle_axis_source(void *data, struct wl_pointer *pointer,
+ uint32_t source)
+{
+ (void) data;
+ (void) pointer;
+ (void) source;
+}
+
+static void
+pointer_handle_axis_stop(void *data, struct wl_pointer *pointer,
+ uint32_t time, uint32_t axis)
+{
+ (void) data;
+ (void) pointer;
+ (void) time;
+ (void) axis;
+}
+
+static void
+pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer,
+ uint32_t axis, int32_t discrete)
+{
+ (void) data;
+ (void) pointer;
+ (void) axis;
+ (void) discrete;
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
+ pointer_handle_frame,
+ pointer_handle_axis_source,
+ pointer_handle_axis_stop,
+ pointer_handle_axis_discrete
+};
+
+/*
+ * touch callbcak functions
+ */
+
+static void
+touch_handle_down(void *data, struct wl_touch *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 display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_down(window, serial, time, id, x_w, y_w);
+}
+
+static void
+touch_handle_up(void *data, struct wl_touch *touch, uint32_t serial,
+ uint32_t time, int32_t id)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_up(window, serial, time, id);
+}
+
+static void
+touch_handle_motion(void *data, struct wl_touch *touch, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_motion(window, time, id, x_w, y_w);
+}
+
+static void
+touch_handle_frame(void *data, struct wl_touch *touch)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_frame(window);
+}
+
+static void
+touch_handle_cancel(void *data, struct wl_touch *touch)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_cancel(window);
+}
+
+static void
+touch_handle_shape(void *data, struct wl_touch *touch,
+ int32_t id, wl_fixed_t maj, wl_fixed_t min)
+{
+ (void) data;
+ (void) touch;
+
+ (void) id;
+ (void) maj;
+ (void) min;
+}
+
+static void
+touch_handle_orientation(void *data, struct wl_touch *touch, int32_t id, wl_fixed_t orientation)
+{
+ (void) data;
+ (void) touch;
+
+ (void) id;
+ (void) orientation;
+}
+
+static const struct wl_touch_listener touch_listener = {
+ touch_handle_down,
+ touch_handle_up,
+ touch_handle_motion,
+ touch_handle_frame,
+ touch_handle_cancel,
+ touch_handle_shape,
+ touch_handle_orientation,
+};
+
+static void
+xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
+{
+ xdg_wm_base_pong(shell, serial);
+}
+
+static const struct xdg_wm_base_listener xdg_wm_base_listener = {
+ xdg_wm_base_ping,
+};
+
+
+/*
+ * seat callback
+ */
+static void
+seat_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps)
+{
+ struct display *display = data;
+
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !display->wl_pointer) {
+ display->wl_pointer = wl_seat_get_pointer(wl_seat);
+ wl_pointer_set_user_data(display->wl_pointer, display);
+ wl_pointer_add_listener(display->wl_pointer, &pointer_listener, display);
+ wl_display_roundtrip(display->display);
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && display->wl_pointer) {
+ wl_pointer_destroy(display->wl_pointer);
+ display->wl_pointer = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !display->wl_touch) {
+ display->wl_touch = wl_seat_get_touch(wl_seat);
+ wl_touch_set_user_data(display->wl_touch, display);
+ wl_touch_add_listener(display->wl_touch, &touch_listener, display);
+ wl_display_roundtrip(display->display);
+ } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && display->wl_touch) {
+ wl_touch_destroy(display->wl_touch);
+ display->wl_touch = NULL;
+ }
+}
+
+static const struct wl_seat_listener seat_listener = {
+ seat_capabilities,
+ NULL
+};
+
+static void
+add_seat(struct display *display, uint32_t id, uint32_t version)
+{
+ display->wl_pointer = NULL;
+ display->wl_touch = NULL;
+ display->wl_keyboard = NULL;
+ display->seat = wl_registry_bind(display->registry, id,
+ &wl_seat_interface, 1);
+ wl_seat_add_listener(display->seat, &seat_listener, display);
+}
+
+/*
+ * registry callback
+ */
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ struct display *d = data;
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ d->compositor = wl_registry_bind(registry,
+ id, &wl_compositor_interface, 1);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ add_seat(d, id, version);
+ } else if (strcmp(interface, "xdg_wm_base") == 0) {
+ d->wm_base = wl_registry_bind(registry, id,
+ &xdg_wm_base_interface, 1);
+ xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d);
+ }
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name)
+{
+ /* stub */
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove
+};
+
+
+static struct display *
+create_display(void)
+{
+ struct display *display;
+
+ display = malloc(sizeof *display);
+ if (display == NULL) {
+ wth_error("out of memory\n");
+ exit(1);
+ }
+ display->display = wl_display_connect(NULL);
+ assert(display->display);
+
+ display->has_xrgb = false;
+ display->registry = wl_display_get_registry(display->display);
+ wl_registry_add_listener(display->registry,
+ &registry_listener, display);
+
+ wl_display_roundtrip(display->display);
+
+ return display;
+}
+
+static void
+destroy_display(struct display *display)
+{
+ if (display->compositor)
+ wl_compositor_destroy(display->compositor);
+
+ wl_registry_destroy(display->registry);
+ wl_display_flush(display->display);
+ wl_display_disconnect(display->display);
+ free(display);
+}
+
+static bool
+wth_check_egl_extension(const char *extensions, const char *extension)
+{
+ size_t extlen = strlen(extension);
+ const char *end = extensions + strlen(extensions);
+
+ while (extensions < end) {
+ size_t n = 0;
+
+ /* Skip whitespaces, if any */
+ if (*extensions == ' ') {
+ extensions++;
+ continue;
+ }
+
+ n = strcspn(extensions, " ");
+
+ /* Compare strings */
+ if (n == extlen && strncmp(extension, extensions, n) == 0)
+ return true; /* Found */
+
+ extensions += n;
+ }
+
+ /* Not found */
+ return false;
+}
+
+static inline void *
+wth_get_egl_proc_address(const char *address)
+{
+ const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+
+ if (extensions &&
+ (wth_check_egl_extension(extensions, "EGL_EXT_platform_wayland") ||
+ wth_check_egl_extension(extensions, "EGL_KHR_platform_wayland"))) {
+ return (void *) eglGetProcAddress(address);
+ }
+
+ return NULL;
+}
+
+static inline EGLDisplay
+wth_get_egl_display(EGLenum platform, void *native_display,
+ const EGLint *attrib_list)
+{
+ static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
+
+ if (!get_platform_display) {
+ get_platform_display = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
+ wth_get_egl_proc_address("eglGetPlatformDisplayEXT");
+ }
+
+ if (get_platform_display)
+ return get_platform_display(platform, native_display, attrib_list);
+
+ /* FIXME: no fall-through using eglGetDisplay() */
+ return NULL;
+}
+
+static void
+init_egl(struct display *display)
+{
+ EGLint config_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+
+ static const EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ EGLint major, minor, count;
+ EGLBoolean ret;
+
+ display->egl.dpy = wth_get_egl_display(EGL_PLATFORM_WAYLAND_KHR,
+ display->display, NULL);
+ assert(display->egl.dpy);
+
+ ret = eglInitialize(display->egl.dpy, &major, &minor);
+ assert(ret == EGL_TRUE);
+ ret = eglBindAPI(EGL_OPENGL_ES_API);
+ assert(ret == EGL_TRUE);
+
+ ret = eglChooseConfig(display->egl.dpy, config_attribs,
+ &display->egl.conf, 1, &count);
+ assert(ret && count >= 1);
+
+ display->egl.ctx = eglCreateContext(display->egl.dpy,
+ display->egl.conf,
+ EGL_NO_CONTEXT, context_attribs);
+ assert(display->egl.ctx);
+
+ eglSwapInterval(display->egl.dpy, 1);
+
+ display->egl.create_image =
+ (void *) eglGetProcAddress("eglCreateImageKHR");
+ assert(display->egl.create_image);
+
+ display->egl.image_texture_2d =
+ (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
+ assert(display->egl.image_texture_2d);
+
+ display->egl.destroy_image =
+ (void *) eglGetProcAddress("eglDestroyImageKHR");
+ assert(display->egl.destroy_image);
+
+}
+
+GLuint load_shader(GLenum type, const char *shaderSrc)
+{
+
+ GLuint shader;
+ GLint compiled;
+
+ /* Create the shader object */
+ shader = glCreateShader(type);
+ if (shader == 0)
+ {
+ printf("\n Failed to create shader \n");
+ return 0;
+ }
+ /* Load the shader source */
+ glShaderSource(shader, 1, &shaderSrc, NULL);
+ /* Compile the shader */
+ glCompileShader(shader);
+ /* Check the compile status */
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled)
+ {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char*)malloc (sizeof(char) * infoLen );
+ glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
+ fprintf(stderr, "Error compiling shader:%s\n",infoLog);
+ free(infoLog);
+ }
+ glDeleteShader(shader);
+ return 0;
+ }
+ return shader;
+}
+
+void init_gl(struct display *display)
+{
+
+ GLint linked;
+
+ /* load vertext/fragment shader */
+ display->gl.vertex_shader = load_shader(GL_VERTEX_SHADER, vertex_shader_str);
+ display->gl.fragment_shader = load_shader(GL_FRAGMENT_SHADER, fragment_shader_str);
+
+ /* Create the program object */
+ display->gl.program_object = glCreateProgram();
+ if (display->gl.program_object == 0)
+ {
+ fprintf(stderr, "error program object\n");
+ return;
+ }
+
+ glAttachShader(display->gl.program_object, display->gl.vertex_shader);
+ glAttachShader(display->gl.program_object, display->gl.fragment_shader);
+ /* Bind vPosition to attribute 0 */
+ glBindAttribLocation(display->gl.program_object, 0, "a_position");
+ /* Link the program */
+ glLinkProgram(display->gl.program_object);
+ /* Check the link status */
+ glGetProgramiv(display->gl.program_object, GL_LINK_STATUS, &linked);
+ if (!linked)
+ {
+ GLint infoLen = 0;
+ glGetProgramiv(display->gl.program_object, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char*)malloc(sizeof(char) * infoLen);
+ glGetProgramInfoLog(display->gl.program_object, infoLen, NULL, infoLog);
+ fprintf(stderr, "Error linking program:%s\n", infoLog);
+ free(infoLog);
+ }
+ glDeleteProgram(display->gl.program_object);
+ }
+
+ glGenTextures(1, &display->gl.texture);
+
+ return;
+}
+
+static void
+handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
+ int32_t width, int32_t height, struct wl_array *states)
+{
+ struct window *window = data;
+ uint32_t *p;
+
+ window->fullscreen = 0;
+ window->maximized = 0;
+
+ wl_array_for_each(p, states) {
+ uint32_t state = *p;
+ switch (state) {
+ case XDG_TOPLEVEL_STATE_FULLSCREEN:
+ window->fullscreen = 1;
+ break;
+ case XDG_TOPLEVEL_STATE_MAXIMIZED:
+ window->maximized = 1;
+ break;
+ }
+ }
+
+ fprintf(stdout, "Got handle_xdg_toplevel_configure() "
+ "width %d, height %d, full %d, max %d\n", width, height,
+ window->fullscreen, window->maximized);
+
+ if (width > 0 && height > 0) {
+ if (!window->fullscreen && !window->maximized) {
+ window->width = width;
+ window->height = height;
+ }
+ window->width = width;
+ window->height = height;
+ } else if (!window->fullscreen && !window->maximized) {
+ if (width == 0)
+ window->width = WINDOW_WIDTH_SIZE;
+ else
+ window->width = width;
+
+ if (height == 0)
+ window->height = WINDOW_HEIGHT_SIZE;
+ else
+ window->height = height;
+ }
+
+ fprintf(stdout, "settting width %d, height %d\n", window->width,
+ window->height);
+
+ if (window->native) {
+ fprintf(stdout, "wayland-egl to resize to %dx%d\n", window->width, window->height);
+ wl_egl_window_resize(window->native, window->width,
+ window->height, 0, 0);
+ }
+}
+
+
+static void
+handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
+{
+ running = 0;
+}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+ handle_xdg_toplevel_configure,
+ handle_xdg_toplevel_close,
+};
+
+static inline EGLSurface
+wth_create_egl_surface(EGLDisplay dpy, EGLConfig config,
+ void *native_window, const EGLint *attrib_list)
+{
+ static PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC
+ create_platform_window = NULL;
+
+ if (!create_platform_window) {
+ create_platform_window = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
+ wth_get_egl_proc_address("eglCreatePlatformWindowSurfaceEXT");
+ }
+
+ if (create_platform_window)
+ return create_platform_window(dpy, config,
+ native_window, attrib_list);
+
+ return eglCreateWindowSurface(dpy, config,
+ (EGLNativeWindowType) native_window,
+ attrib_list);
+}
+
+static inline EGLBoolean
+wth_destroy_egl_surface(EGLDisplay display, EGLSurface surface)
+{
+ return eglDestroySurface(display, surface);
+}
+
+void
+redraw(struct window *window)
+{
+ struct wl_region *region;
+ struct display *display = window->display;
+
+ if (window->opaque || window->fullscreen) {
+ region = wl_compositor_create_region(window->display->compositor);
+ wl_region_add(region, 0, 0,
+ window->width,
+ window->height);
+ wl_surface_set_opaque_region(window->surface, region);
+ wl_region_destroy(region);
+ } else {
+ wl_surface_set_opaque_region(window->surface, NULL);
+ }
+
+ fprintf(stdout, "Doing a redraw\n");
+ eglSwapBuffers(display->egl.dpy, window->egl_surface);
+}
+
+static void
+handle_xdg_surface_configure(void *data, struct xdg_surface *surface, uint32_t serial)
+{
+ struct window *window = data;
+
+ fprintf(stderr, "Sending configure ack\n");
+ xdg_surface_ack_configure(surface, serial);
+ window->wait_for_configure = false;
+}
+
+static const struct xdg_surface_listener xdg_surface_listener = {
+ handle_xdg_surface_configure,
+};
+
+
+static void
+create_surface(struct window *window)
+{
+
+ struct display *display = window->display;
+ int ret;
+
+ window->surface = wl_compositor_create_surface(display->compositor);
+ assert(window->surface);
+
+ window->native = wl_egl_window_create(window->surface,
+ window->width, window->height);
+ assert(window->native);
+
+ window->egl_surface = wth_create_egl_surface(display->egl.dpy,
+ display->egl.conf,
+ window->native, NULL);
+
+ wl_display_roundtrip(display->display);
+
+ if (display->wm_base) {
+ window->xdg_surface =
+ xdg_wm_base_get_xdg_surface(display->wm_base, window->surface);
+ assert(window->xdg_surface);
+
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
+ window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
+ assert(window->xdg_toplevel);
+
+ xdg_toplevel_add_listener(window->xdg_toplevel,
+ &xdg_toplevel_listener, window);
+
+ if (window->app_id)
+ xdg_toplevel_set_app_id(window->xdg_toplevel, window->app_id);
+
+ wl_surface_commit(window->surface);
+ window->wait_for_configure = true;
+ }
+
+
+ ret = eglMakeCurrent(display->egl.dpy, window->egl_surface,
+ window->egl_surface, display->egl.ctx);
+ assert(ret == EGL_TRUE);
+
+ if (!window->frame_sync)
+ eglSwapInterval(display->egl.dpy, 0);
+
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+static void
+create_window(struct window *window, struct display *display, int width, int height, const char *app_id)
+{
+ window->callback = NULL;
+ window->display = display;
+ window->width = width;
+ window->height = height;
+ window->window_frames = 0;
+ window->window_benchmark_time = 0;
+ window->app_id = app_id;
+ window->frame_sync = 1;
+
+ create_surface(window);
+
+ return;
+}
+
+static void
+destroy_window(struct window *window)
+{
+
+
+ if (window->callback)
+ wl_callback_destroy(window->callback);
+
+ if (window->xdg_toplevel)
+ xdg_toplevel_destroy(window->xdg_toplevel);
+
+ if (window->xdg_surface)
+ xdg_surface_destroy(window->xdg_surface);
+
+
+ wl_surface_destroy(window->surface);
+ free(window);
+
+
+}
+
+static void
+signal_int(int signum)
+{
+ running = 0;
+}
+
+
+static void
+error_cb(GstBus *bus, GstMessage *msg, gpointer user_data)
+{
+ GstAppContext *d = user_data;
+
+ gchar *debug = NULL;
+ GError *err = NULL;
+
+ gst_message_parse_error(msg, &err, &debug);
+
+ g_print("Error: %s\n", err->message);
+ g_error_free(err);
+
+ if (debug) {
+ g_print("Debug details: %s\n", debug);
+ g_free(debug);
+ }
+
+ gst_element_set_state(d->pipeline, GST_STATE_NULL);
+}
+
+static GstBusSyncReply
+bus_sync_handler(GstBus *bus, GstMessage *message, gpointer user_data)
+{
+ GstAppContext *d = user_data;
+
+ fprintf(stdout, "entering bus_sync_handler() setting it\n");
+
+ if (gst_is_wayland_display_handle_need_context_message(message)) {
+ GstContext *context;
+ struct wl_display *display_handle = d->display->display;
+
+ context = gst_wayland_display_handle_context_new(display_handle);
+ d->wl_video = GST_WAYLAND_VIDEO(GST_MESSAGE_SRC(message));
+ gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message)), context);
+
+ fprintf(stdout, "bus_sync_handler(): creating context and setting it\n");
+
+ goto drop;
+ } else if (gst_is_video_overlay_prepare_window_handle_message(message)) {
+ struct wl_surface *window_handle = d->window->surface;
+
+ /* GST_MESSAGE_SRC(message) will be the overlay object that we
+ * have to use. This may be waylandsink, but it may also be
+ * playbin. In the latter case, we must make sure to use
+ * playbin instead of waylandsink, because playbin resets the
+ * window handle and render_rectangle after restarting playback
+ * and the actual window size is lost */
+ d->overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(message));
+
+ g_print("setting window handle and size (%d x %d) w %d, h %d\n",
+ d->window->x, d->window->y,
+ d->window->width, d->window->height);
+
+ gst_video_overlay_set_window_handle(d->overlay, (guintptr) window_handle);
+ gst_video_overlay_set_render_rectangle(d->overlay,
+ d->window->x, d->window->y,
+ d->window->width, d->window->height);
+
+ goto drop;
+ }
+
+ return GST_BUS_PASS;
+
+drop:
+ gst_message_unref(message);
+ return GST_BUS_DROP;
+}
+
+
+/**
+ * wth_receiver_weston_main
+ *
+ * This is the main function which will handle connection to the compositor at
+ * receiver side
+ *
+ * @param names void *data
+ * @param value struct window data
+ * @return 0 on success, -1 on error
+ */
+int
+wth_receiver_weston_main(struct window *window, const char *app_id, int port)
+{
+ struct sigaction sigint;
+ GstAppContext gstctx;
+ int ret = 0;
+ GError *gerror = NULL;
+ char pipeline[PIPELINE_SIZE];
+
+ memset(&gstctx, 0, sizeof(gstctx));
+
+ sigint.sa_handler = signal_int;
+ sigemptyset(&sigint.sa_mask);
+ sigint.sa_flags = SA_RESETHAND;
+ sigaction(SIGINT, &sigint, NULL);
+
+ /* Initialization for window creation */
+ gstctx.display = create_display();
+ init_egl(gstctx.display);
+
+ /* ToDo: fix the hardcoded value of width, height */
+ create_window(window, gstctx.display, WINDOW_WIDTH_SIZE,
+ WINDOW_HEIGHT_SIZE, app_id);
+ init_gl(gstctx.display);
+
+ gstctx.window = window;
+ gstctx.display->window = window;
+
+ fprintf(stderr, "display %p\n", gstctx.display);
+ fprintf(stderr, "display->window %p\n", gstctx.display->window);
+ fprintf(stderr, "window %p\n", window);
+
+ int gargc = 2;
+ char **gargv = (char**) malloc(2 * sizeof(char*));
+
+ gargv[0] = strdup("waltham-receiver");
+ gargv[1] = strdup("--gst-debug-level=2");
+
+ /* create gstreamer pipeline */
+ gst_init(&gargc, &gargv);
+
+ const char *pipe = "rtpbin name=rtpbin udpsrc "
+ "caps=\"application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=JPEG,payload=26\" "
+ "port=%d ! rtpbin.recv_rtp_sink_0 rtpbin. ! "
+ "rtpjpegdepay ! jpegdec ! waylandsink";
+
+ memset(pipeline, 0x00, sizeof(pipeline));
+ snprintf(pipeline, sizeof(pipeline), pipe, port);
+
+ fprintf(stdout, "pipeline %s\n", pipeline);
+
+ /* parse the pipeline */
+ gstctx.pipeline = gst_parse_launch(pipeline, &gerror);
+ if (!gstctx.pipeline) {
+ fprintf(stderr, "Could not create gstreamer pipeline.\n");
+ destroy_display(gstctx.display);
+ return -1;
+ }
+
+ gstctx.bus = gst_element_get_bus(gstctx.pipeline);
+ gst_bus_add_signal_watch(gstctx.bus);
+
+ g_signal_connect(gstctx.bus, "message::error", G_CALLBACK(error_cb), &gstctx);
+ gst_bus_set_sync_handler(gstctx.bus, bus_sync_handler, &gstctx, NULL);
+ gst_object_unref(gstctx.bus);
+
+ gst_element_set_state(gstctx.pipeline, GST_STATE_PLAYING);
+
+ while (running && ret != -1) {
+ if (window->wait_for_configure) {
+ ret = wl_display_dispatch(gstctx.display->display);
+ } else {
+ ret = wl_display_dispatch_pending(gstctx.display->display);
+ redraw(window);
+ }
+ }
+
+ gst_element_set_state(gstctx.pipeline, GST_STATE_NULL);
+
+ destroy_window(window);
+ destroy_display(gstctx.display);
+ gst_object_unref(gstctx.pipeline);
+
+ return 0;
+}
diff --git a/src/wth-receiver-gst-shm.c b/src/wth-receiver-gst-shm.c
new file mode 100644
index 0000000..54950ef
--- /dev/null
+++ b/src/wth-receiver-gst-shm.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*******************************************************************************
+ ** **
+ ** TARGET : linux **
+ ** **
+ ** PROJECT : waltham-receiver **
+ ** **
+ ** PURPOSE : This file is acts as interface to weston compositor at receiver **
+ ** side **
+ ** **
+ *******************************************************************************/
+
+#define GST_USE_UNSTABLE_API
+
+#include <sys/mman.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include <gst/gst.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/allocators/gstdmabuf.h>
+#include <gst/app/gstappsink.h>
+
+#include <pthread.h>
+#include <gst/wayland/wayland.h>
+#include <gst/video/videooverlay.h>
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "xdg-shell-client-protocol.h"
+
+#include "wth-receiver-comm.h"
+#include "wth-receiver-seat.h"
+#include "os-compatibility.h"
+#include "bitmap.h"
+
+#define WINDOW_WIDTH_SIZE 1920
+#define WINDOW_HEIGHT_SIZE 760
+
+#define PIPELINE_SIZE 4096
+
+static int running = 1;
+
+typedef struct _GstAppContext {
+ GMainLoop *loop;
+ GstBus *bus;
+
+ GstElement *pipeline;
+ GstElement *sink;
+
+ GstWaylandVideo *wl_video;
+ GstVideoOverlay *overlay;
+
+ struct display *display;
+ struct window *window;
+ GstVideoInfo info;
+
+} GstAppContext;
+
+/*
+ * pointer callbcak functions
+ */
+static void
+pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, struct wl_surface *wl_surface,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_enter(window, serial, sx, sy);
+}
+
+static void
+pointer_handle_leave(void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_leave(window, serial);
+}
+
+static void
+pointer_handle_motion(void *data, struct wl_pointer *pointer,
+ uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_motion(window, time, sx, sy);
+}
+
+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 display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_button(window, serial, time, button, state);
+}
+
+static void
+pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_axis(window, time, axis, value);
+}
+
+static void
+pointer_handle_frame(void *data, struct wl_pointer *pointer)
+{
+ (void) data;
+ (void) pointer;
+}
+
+static void
+pointer_handle_axis_source(void *data, struct wl_pointer *pointer,
+ uint32_t source)
+{
+ (void) data;
+ (void) pointer;
+ (void) source;
+}
+
+static void
+pointer_handle_axis_stop(void *data, struct wl_pointer *pointer,
+ uint32_t time, uint32_t axis)
+{
+ (void) data;
+ (void) pointer;
+ (void) time;
+ (void) axis;
+}
+
+static void
+pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer,
+ uint32_t axis, int32_t discrete)
+{
+ (void) data;
+ (void) pointer;
+ (void) axis;
+ (void) discrete;
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
+ pointer_handle_frame,
+ pointer_handle_axis_source,
+ pointer_handle_axis_stop,
+ pointer_handle_axis_discrete
+};
+
+/*
+ * touch callbcak functions
+ */
+static void
+touch_handle_down(void *data, struct wl_touch *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 display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_down(window, serial, time, id, x_w, y_w);
+}
+
+static void
+touch_handle_up(void *data, struct wl_touch *touch, uint32_t serial,
+ uint32_t time, int32_t id)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_up(window, serial, time, id);
+}
+
+static void
+touch_handle_motion(void *data, struct wl_touch *touch, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_motion(window, time, id, x_w, y_w);
+}
+
+static void
+touch_handle_frame(void *data, struct wl_touch *touch)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_frame(window);
+}
+
+static void
+touch_handle_cancel(void *data, struct wl_touch *touch)
+{
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_cancel(window);
+}
+
+static void
+touch_handle_shape(void *data, struct wl_touch *touch,
+ int32_t id, wl_fixed_t maj, wl_fixed_t min)
+{
+ (void) data;
+ (void) touch;
+
+ (void) id;
+ (void) maj;
+ (void) min;
+}
+
+static void
+touch_handle_orientation(void *data, struct wl_touch *touch, int32_t id, wl_fixed_t orientation)
+{
+ (void) data;
+ (void) touch;
+
+ (void) id;
+ (void) orientation;
+}
+
+static const struct wl_touch_listener touch_listener = {
+ touch_handle_down,
+ touch_handle_up,
+ touch_handle_motion,
+ touch_handle_frame,
+ touch_handle_cancel,
+ touch_handle_shape,
+ touch_handle_orientation,
+};
+
+static void
+xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
+{
+ xdg_wm_base_pong(shell, serial);
+}
+
+static const struct xdg_wm_base_listener xdg_wm_base_listener = {
+ xdg_wm_base_ping,
+};
+
+
+/*
+ * seat callback
+ */
+static void
+seat_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps)
+{
+ struct display *display = data;
+
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !display->wl_pointer) {
+ display->wl_pointer = wl_seat_get_pointer(wl_seat);
+ wl_pointer_set_user_data(display->wl_pointer, display);
+ wl_pointer_add_listener(display->wl_pointer, &pointer_listener, display);
+ wl_display_roundtrip(display->display);
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && display->wl_pointer) {
+ wl_pointer_destroy(display->wl_pointer);
+ display->wl_pointer = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !display->wl_touch) {
+ display->wl_touch = wl_seat_get_touch(wl_seat);
+ wl_touch_set_user_data(display->wl_touch, display);
+ wl_touch_add_listener(display->wl_touch, &touch_listener, display);
+ wl_display_roundtrip(display->display);
+ } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && display->wl_touch) {
+ wl_touch_destroy(display->wl_touch);
+ display->wl_touch = NULL;
+ }
+}
+
+static const struct wl_seat_listener seat_listener = {
+ seat_capabilities,
+ NULL
+};
+
+static void
+add_seat(struct display *display, uint32_t id, uint32_t version)
+{
+ display->wl_pointer = NULL;
+ display->wl_touch = NULL;
+ display->wl_keyboard = NULL;
+ display->seat = wl_registry_bind(display->registry, id,
+ &wl_seat_interface, 1);
+ wl_seat_add_listener(display->seat, &seat_listener, display);
+}
+
+static void
+redraw(void *data, struct wl_callback *callback, uint32_t time);
+
+static void
+paint_pixels(void *image, int padding, int width, int height, uint32_t time)
+{
+ memset(image, 0x00, width * height * 4);
+}
+
+static void
+buffer_release(void *data, struct wl_buffer *buffer)
+{
+ struct shm_buffer *mybuf = data;
+ mybuf->busy = 0;
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+ buffer_release
+};
+
+static int
+create_shm_buffer(struct display *display, struct shm_buffer *buffer,
+ int width, int height, uint32_t format)
+{
+ struct wl_shm_pool *pool;
+ int fd, size, stride;
+ void *data;
+
+ stride = width * 4;
+ size = stride * height;
+
+ fd = os_create_anonymous_file(size);
+ if (fd < 0) {
+ fprintf(stderr, "creating a buffer file for %d B failed: %s\n",
+ size, strerror(errno));
+ return -1;
+ }
+
+ data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED) {
+ fprintf(stderr, "mmap failed: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ pool = wl_shm_create_pool(display->shm, fd, size);
+ buffer->buffer = wl_shm_pool_create_buffer(pool, 0, width,
+ height, stride, format);
+ wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ buffer->shm_data = data;
+ return 0;
+}
+
+static struct shm_buffer *
+get_next_buffer(struct window *window)
+{
+ struct shm_buffer *buffer;
+ int ret = 0;
+
+ if (!window->buffers[0].busy)
+ buffer = &window->buffers[0];
+ else if (!window->buffers[1].busy)
+ buffer = &window->buffers[1];
+ else
+ return NULL;
+
+ if (!buffer->buffer) {
+ fprintf(stdout, "get_next_buffer() buffer is not set, setting with "
+ "width %d, height %d\n", window->width, window->height);
+ ret = create_shm_buffer(window->display, buffer, window->width,
+ window->height, WL_SHM_FORMAT_XRGB8888);
+
+ if (ret < 0)
+ return NULL;
+
+ /* paint the padding */
+ memset(buffer->shm_data, 0x00, window->width * window->height * 4);
+ }
+
+ return buffer;
+}
+
+
+static const struct wl_callback_listener frame_listener = {
+ redraw
+};
+
+static void
+redraw(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct window *window = data;
+ struct shm_buffer *buffer;
+
+ buffer = get_next_buffer(window);
+ if (!buffer) {
+ fprintf(stderr,
+ !callback ? "Failed to create the first buffer.\n" :
+ "Both buffers busy at redraw(). Server bug?\n");
+ abort();
+ }
+
+ // do the actual painting
+ paint_pixels(buffer->shm_data, 0x0, window->width, window->height, time);
+
+ wl_surface_attach(window->surface, buffer->buffer, 0, 0);
+ wl_surface_damage(window->surface, 0, 0, window->width, window->height);
+
+ if (callback)
+ wl_callback_destroy(callback);
+
+ window->callback = wl_surface_frame(window->surface);
+ wl_callback_add_listener(window->callback, &frame_listener, window);
+ wl_surface_commit(window->surface);
+
+ buffer->busy = 1;
+}
+
+static void
+shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+ struct display *d = data;
+
+ if (format == WL_SHM_FORMAT_XRGB8888)
+ d->has_xrgb = true;
+}
+
+static const struct wl_shm_listener shm_listener = {
+ shm_format
+};
+
+static void
+handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
+ int32_t width, int32_t height, struct wl_array *states)
+{
+ struct window *window = data;
+ uint32_t *p;
+
+ window->fullscreen = 0;
+ window->maximized = 0;
+
+ wl_array_for_each(p, states) {
+ uint32_t state = *p;
+ switch (state) {
+ case XDG_TOPLEVEL_STATE_FULLSCREEN:
+ window->fullscreen = 1;
+ break;
+ case XDG_TOPLEVEL_STATE_MAXIMIZED:
+ window->maximized = 1;
+ break;
+ }
+ }
+
+ fprintf(stdout, "Got handle_xdg_toplevel_configure() "
+ "width %d, height %d, full %d, max %d\n", width, height,
+ window->fullscreen, window->maximized);
+
+ if (width > 0 && height > 0) {
+ if (!window->fullscreen && !window->maximized) {
+ window->width = width;
+ window->height = height;
+ }
+ window->width = width;
+ window->height = height;
+ } else if (!window->fullscreen && !window->maximized) {
+ if (width == 0)
+ window->width = WINDOW_WIDTH_SIZE;
+ else
+ window->width = width;
+
+ if (height == 0)
+ window->height = WINDOW_HEIGHT_SIZE;
+ else
+ window->height = height;
+ }
+
+ fprintf(stdout, "settting width %d, height %d\n", window->width,
+ window->height);
+}
+
+
+static void
+handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
+{
+ running = 0;
+}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+ handle_xdg_toplevel_configure,
+ handle_xdg_toplevel_close,
+};
+
+static void
+handle_xdg_surface_configure(void *data, struct xdg_surface *surface, uint32_t serial)
+{
+ struct window *window = data;
+
+ fprintf(stderr, "Sending configure ack\n");
+
+ xdg_surface_ack_configure(surface, serial);
+
+ if (window->wait_for_configure) {
+ redraw(window, NULL, 0);
+ window->wait_for_configure = false;
+ }
+}
+
+static const struct xdg_surface_listener xdg_surface_listener = {
+ handle_xdg_surface_configure,
+};
+
+
+static void
+create_surface(struct window *window)
+{
+ struct display *display = window->display;
+
+ window->surface = wl_compositor_create_surface(display->compositor);
+ assert(window->surface);
+
+ if (display->wm_base) {
+ window->xdg_surface =
+ xdg_wm_base_get_xdg_surface(display->wm_base, window->surface);
+ assert(window->xdg_surface);
+
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
+ window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
+ assert(window->xdg_toplevel);
+
+ xdg_toplevel_add_listener(window->xdg_toplevel,
+ &xdg_toplevel_listener, window);
+
+ if (window->app_id)
+ xdg_toplevel_set_app_id(window->xdg_toplevel, window->app_id);
+
+ wl_surface_commit(window->surface);
+ window->wait_for_configure = true;
+ }
+}
+
+static void
+create_window(struct window *window, struct display *display, int width, int height, const char *app_id)
+{
+ window->callback = NULL;
+
+ window->display = display;
+ window->width = width;
+ window->height = height;
+ window->window_frames = 0;
+ window->window_benchmark_time = 0;
+ window->app_id = app_id;
+ window->frame_sync = 1;
+
+ create_surface(window);
+
+ return;
+}
+
+static void
+destroy_window(struct window *window)
+{
+ if (window->callback)
+ wl_callback_destroy(window->callback);
+
+ if (window->xdg_toplevel)
+ xdg_toplevel_destroy(window->xdg_toplevel);
+
+ if (window->xdg_surface)
+ xdg_surface_destroy(window->xdg_surface);
+
+
+ wl_surface_destroy(window->surface);
+ free(window);
+}
+
+static void
+signal_int(int signum)
+{
+ running = 0;
+}
+
+/*
+ * registry callback
+ */
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ struct display *d = data;
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ d->compositor =
+ wl_registry_bind(registry,
+ id, &wl_compositor_interface, 1);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ add_seat(d, id, version);
+ } else if (strcmp(interface, "xdg_wm_base") == 0) {
+ d->wm_base = wl_registry_bind(registry, id,
+ &xdg_wm_base_interface, 1);
+ xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d);
+
+ } else if (strcmp(interface, "wl_shm") == 0) {
+ d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
+ wl_shm_add_listener(d->shm, &shm_listener, d);
+ }
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name)
+{
+ /* stub */
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove
+};
+
+
+static struct display *
+create_display(void)
+{
+ struct display *display;
+
+ display = malloc(sizeof *display);
+ if (display == NULL) {
+ wth_error("out of memory\n");
+ exit(1);
+ }
+ display->display = wl_display_connect(NULL);
+ assert(display->display);
+
+ display->has_xrgb = false;
+ display->registry = wl_display_get_registry(display->display);
+ wl_registry_add_listener(display->registry,
+ &registry_listener, display);
+
+ wl_display_roundtrip(display->display);
+
+ return display;
+}
+
+static void
+destroy_display(struct display *display)
+{
+ if (display->compositor)
+ wl_compositor_destroy(display->compositor);
+
+ wl_registry_destroy(display->registry);
+ wl_display_flush(display->display);
+ wl_display_disconnect(display->display);
+ free(display);
+}
+
+static void
+error_cb(GstBus *bus, GstMessage *msg, gpointer user_data)
+{
+ GstAppContext *d = user_data;
+
+ gchar *debug = NULL;
+ GError *err = NULL;
+
+ gst_message_parse_error(msg, &err, &debug);
+
+ g_print("Error: %s\n", err->message);
+ g_error_free(err);
+
+ if (debug) {
+ g_print("Debug details: %s\n", debug);
+ g_free(debug);
+ }
+
+ gst_element_set_state(d->pipeline, GST_STATE_NULL);
+}
+
+static GstBusSyncReply
+bus_sync_handler(GstBus *bus, GstMessage *message, gpointer user_data)
+{
+ GstAppContext *d = user_data;
+
+ if (gst_is_wayland_display_handle_need_context_message(message)) {
+ GstContext *context;
+ struct wl_display *display_handle = d->display->display;
+
+ context = gst_wayland_display_handle_context_new(display_handle);
+ d->wl_video = GST_WAYLAND_VIDEO(GST_MESSAGE_SRC(message));
+ gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(message)), context);
+
+ goto drop;
+ } else if (gst_is_video_overlay_prepare_window_handle_message(message)) {
+ struct wl_surface *window_handle = d->window->surface;
+
+ /* GST_MESSAGE_SRC(message) will be the overlay object that we
+ * have to use. This may be waylandsink, but it may also be
+ * playbin. In the latter case, we must make sure to use
+ * playbin instead of waylandsink, because playbin resets the
+ * window handle and render_rectangle after restarting playback
+ * and the actual window size is lost */
+ d->overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(message));
+
+ g_print("setting window handle and size (%d x %d) w %d, h %d\n",
+ d->window->x, d->window->y,
+ d->window->width, d->window->height);
+
+ gst_video_overlay_set_window_handle(d->overlay, (guintptr) window_handle);
+ gst_video_overlay_set_render_rectangle(d->overlay,
+ d->window->x, d->window->y,
+ d->window->width, d->window->height);
+
+ goto drop;
+ }
+
+ return GST_BUS_PASS;
+
+drop:
+ gst_message_unref(message);
+ return GST_BUS_DROP;
+}
+
+
+/**
+ * wth_receiver_weston_main
+ *
+ * This is the main function which will handle connection to the compositor at
+ * receiver side
+ *
+ * @param names void *data
+ * @param value struct window data
+ * @return 0 on success, -1 on error
+ */
+int
+wth_receiver_weston_main(struct window *window, const char *app_id, int port)
+{
+ struct sigaction sigint;
+ GstAppContext gstctx;
+ int ret = 0;
+ GError *gerror = NULL;
+ char pipeline[PIPELINE_SIZE];
+
+ memset(&gstctx, 0, sizeof(gstctx));
+
+ sigint.sa_handler = signal_int;
+ sigemptyset(&sigint.sa_mask);
+ sigint.sa_flags = SA_RESETHAND;
+ sigaction(SIGINT, &sigint, NULL);
+
+ /* Initialization for window creation */
+ gstctx.display = create_display();
+
+ /* ToDo: fix the hardcoded value of width, height */
+ create_window(window, gstctx.display, WINDOW_WIDTH_SIZE,
+ WINDOW_HEIGHT_SIZE, app_id);
+
+ gstctx.window = window;
+ gstctx.display->window = window;
+
+ fprintf(stderr, "display %p\n", gstctx.display);
+ fprintf(stderr, "display->window %p\n", gstctx.display->window);
+ fprintf(stderr, "window %p\n", window);
+
+ /* Initialise damage to full surface, so the padding gets painted */
+ wl_surface_damage(window->surface, 0, 0,
+ window->width, window->height);
+
+ if (!window->wait_for_configure)
+ redraw(window, NULL, 0);
+
+ int gargc = 2;
+ char **gargv = (char**) malloc(2 * sizeof(char*));
+
+ gargv[0] = strdup("waltham-receiver");
+ gargv[1] = strdup("--gst-debug-level=2");
+
+ /* create gstreamer pipeline */
+ gst_init(&gargc, &gargv);
+
+ const char *pipe = "rtpbin name=rtpbin udpsrc "
+ "caps=\"application/x-rtp,media=(string)video,clock-rate=(int)90000,encoding-name=JPEG,payload=26\" "
+ "port=%d ! rtpbin.recv_rtp_sink_0 rtpbin. ! "
+ "rtpjpegdepay ! jpegdec ! waylandsink";
+
+ memset(pipeline, 0x00, sizeof(pipeline));
+ snprintf(pipeline, sizeof(pipeline), pipe, port);
+
+ fprintf(stdout, "pipeline %s\n", pipeline);
+
+ /* parse the pipeline */
+ gstctx.pipeline = gst_parse_launch(pipeline, &gerror);
+ if (!gstctx.pipeline)
+ fprintf(stderr, "Could not create gstreamer pipeline.\n");
+
+ gstctx.bus = gst_element_get_bus(gstctx.pipeline);
+ gst_bus_add_signal_watch(gstctx.bus);
+
+ fprintf(stdout, "registered bus signal\n");
+
+ g_signal_connect(gstctx.bus, "message::error", G_CALLBACK(error_cb), &gstctx);
+ gst_bus_set_sync_handler(gstctx.bus, bus_sync_handler, &gstctx, NULL);
+ gst_object_unref(gstctx.bus);
+
+ gst_element_set_state(gstctx.pipeline, GST_STATE_PLAYING);
+
+ while (running && ret != -1)
+ ret = wl_display_dispatch(gstctx.display->display);
+
+ gst_element_set_state(gstctx.pipeline, GST_STATE_NULL);
+
+ destroy_window(window);
+ destroy_display(gstctx.display);
+ gst_object_unref(gstctx.pipeline);
+ free(gargv);
+
+ return 0;
+}
diff --git a/src/wth-receiver-main.c b/src/wth-receiver-main.c
new file mode 100644
index 0000000..8af8eda
--- /dev/null
+++ b/src/wth-receiver-main.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*******************************************************************************
+** **
+** TARGET : linux **
+** **
+** PROJECT : waltham-receiver **
+** **
+** PURPOSE : This file handles connection with remote-client **
+** **
+*******************************************************************************/
+
+#include <signal.h>
+#include "wth-receiver-comm.h"
+
+#define MAX_EPOLL_WATCHES 2
+#define DEFAULT_TCP_PORT 34400
+
+uint16_t tcp_port = 0;
+const char *my_app_id = NULL;
+static bool *signal_int_handler_run_flag;
+
+/** Print out the application help
+ */
+static void
+usage(void)
+{
+ printf("Usage: waltham receiver [options]\n");
+ printf("Options:\n");
+ printf(" -p --port number TCP port number\n");
+ printf(" -i --app_id Specify an app_id\n");
+ printf(" -h --help Usage\n");
+}
+
+static struct option long_options[] = {
+ {"port", required_argument, 0, 'p'},
+ {"app_id", required_argument, NULL, 'i'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+};
+
+/**
+ * parse_args
+ *
+ * Parses the application arguments
+ * The arguments are parsed and saved in static structure for future use.
+ *
+ * @param argc The amount of arguments
+ * @param argv The table of arguments
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int
+parse_args(int argc, char *argv[])
+{
+ int c = -1;
+ int long_index = 0;
+
+ while ((c = getopt_long(argc, argv, "i:p:vh",
+ long_options,
+ &long_index)) != -1) {
+ switch (c) {
+ case 'i':
+ my_app_id = optarg;
+ break;
+ case 'p':
+ tcp_port = (uint16_t) atoi(optarg);
+ break;
+ case 'v':
+ printf("No verbose logs for release mode");
+ break;
+ case 'h':
+ usage();
+ return -1;
+ default:
+ wth_error("Try %s -h for more information.\n", argv[0]);
+ return -1;
+ }
+ }
+
+ if (tcp_port == 0) {
+ tcp_port = DEFAULT_TCP_PORT;
+ }
+
+
+ return 0;
+}
+
+static int
+watch_ctl(struct watch *w, int op, uint32_t events)
+{
+ struct epoll_event ee;
+
+ ee.events = events;
+ ee.data.ptr = w;
+ return epoll_ctl(w->receiver->epoll_fd, op, w->fd, &ee);
+}
+
+/**
+* listen_socket_handle_data
+*
+* Handles all incoming events on socket
+*
+* @param names struct watch *w ,uint32_t events
+* @param value pointer to watch connection it holds receiver information, Incoming events information
+* @return none
+*/
+static void
+listen_socket_handle_data(struct watch *w, uint32_t events)
+{
+ struct receiver *srv = container_of(w, struct receiver, listen_watch);
+
+ if (events & EPOLLERR) {
+ wth_error("Listening socket errored out.\n");
+ srv->running = false;
+ return;
+ }
+
+ if (events & EPOLLHUP) {
+ wth_error("Listening socket hung up.\n");
+ srv->running = false;
+ return;
+ }
+
+ if (events & EPOLLIN) {
+ receiver_accept_client(srv);
+ }
+}
+
+/**
+* receiver_mainloop
+*
+* This is the main loop, which will flush all pending clients requests and
+* listen to input events from socket
+*
+* @param names void *data
+* @param value pointer to receiver struct -
+* struct holds the client connection information
+* @return none
+*/
+static void
+receiver_mainloop(struct receiver *srv)
+{
+ struct epoll_event ee[MAX_EPOLL_WATCHES];
+ struct watch *w;
+ int count;
+ int i;
+
+ srv->running = true;
+
+ while (srv->running) {
+ /* Run any idle tasks at this point. */
+
+ receiver_flush_clients(srv);
+
+ /* Wait for events or signals */
+ count = epoll_wait(srv->epoll_fd,
+ ee, ARRAY_LENGTH(ee), -1);
+ if (count < 0 && errno != EINTR) {
+ perror("Error with epoll_wait");
+ break;
+ }
+
+ /* Handle all fds, both the listening socket
+ * (see listen_socket_handle_data()) and clients
+ * (see connection_handle_data()).
+ */
+ for (i = 0; i < count; i++) {
+ w = ee[i].data.ptr;
+ w->cb(w, ee[i].events);
+ }
+ }
+}
+
+static int
+receiver_listen(uint16_t tcp_port)
+{
+ int fd;
+ int reuse = 1;
+ struct sockaddr_in addr;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(tcp_port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse);
+
+ if (bind(fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
+ wth_error("Failed to bind to port %d", tcp_port);
+ close(fd);
+ return -1;
+ }
+
+ if (listen(fd, 1024) < 0) {
+ wth_error("Failed to listen to port %d", tcp_port);
+ close (fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+
+static void
+signal_int_handler(int signum)
+{
+ if (!*signal_int_handler_run_flag)
+ abort();
+
+ *signal_int_handler_run_flag = false;
+}
+
+static void
+set_sigint_handler(bool *running)
+{
+ struct sigaction sigint;
+
+ signal_int_handler_run_flag = running;
+ sigint.sa_handler = signal_int_handler;
+ sigemptyset(&sigint.sa_mask);
+ sigint.sa_flags = SA_RESETHAND;
+ sigaction(SIGINT, &sigint, NULL);
+}
+
+/**
+ * main
+ *
+ * waltham receiver main function, it accepts tcp port number as argument.
+ * Establishes connection on the port and listen to port for incoming connection
+ * request from waltham clients
+ *
+ * @param names argv - argument list and argc -argument count
+ * @param value tcp port number as argument
+ * @return 0 on success, -1 on error
+ */
+int main(int argc, char *argv[])
+{
+ struct receiver srv = { 0 };
+ struct client *c;
+
+ /* Get command line arguments */
+ if (parse_args(argc, argv) != 0) {
+ return -1;
+ }
+
+ set_sigint_handler(&srv.running);
+
+ wl_list_init(&srv.client_list);
+
+ srv.epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (srv.epoll_fd == -1) {
+ perror("Error on epoll_create1");
+ exit(1);
+ }
+
+ srv.listen_fd = receiver_listen(tcp_port);
+ if (srv.listen_fd < 0) {
+ perror("Error setting up listening socket");
+ exit(1);
+ }
+
+ srv.listen_watch.receiver = &srv;
+ srv.listen_watch.cb = listen_socket_handle_data;
+ srv.listen_watch.fd = srv.listen_fd;
+ if (watch_ctl(&srv.listen_watch, EPOLL_CTL_ADD, EPOLLIN) < 0) {
+ perror("Error setting up listen polling");
+ exit(1);
+ }
+
+ receiver_mainloop(&srv);
+
+ /* destroy all things */
+ wl_list_last_until_empty(c, &srv.client_list, link)
+ client_destroy(c);
+
+ close(srv.listen_fd);
+ close(srv.epoll_fd);
+
+ return 0;
+}
diff --git a/src/wth-receiver-seat.c b/src/wth-receiver-seat.c
new file mode 100644
index 0000000..3457748
--- /dev/null
+++ b/src/wth-receiver-seat.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wth-receiver-comm.h"
+#include "wth-receiver-seat.h"
+
+/*
+ * APIs to send touch events to waltham client
+ */
+void
+waltham_touch_down(struct window *window, uint32_t serial,
+ uint32_t time, int32_t id,
+ wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct surface *surface = window->receiver_surf;
+ struct seat *seat = window->receiver_seat;
+ struct touch *touch = seat->touch;
+
+ if (touch->obj) {
+ fprintf(stdout, "waltham_touch_down() sending touch_down\n");
+ wthp_touch_send_down(touch->obj, serial, time, surface->obj, id, x_w, y_w);
+ }
+ return;
+}
+
+void
+waltham_touch_up(struct window *window, uint32_t serial,
+ uint32_t time, int32_t id)
+{
+ struct seat *seat = window->receiver_seat;
+ struct touch *touch = seat->touch;
+
+ if (touch->obj) {
+ fprintf(stdout, "waltham_touch_motion() sending touch_up\n");
+ wthp_touch_send_up(touch->obj, serial, time, id);
+ }
+ return;
+}
+
+void
+waltham_touch_motion(struct window *window, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct seat *seat = window->receiver_seat;
+ struct touch *touch = seat->touch;
+
+ if (touch->obj) {
+ fprintf(stdout, "waltham_touch_motion() sending touch_motion\n");
+ wthp_touch_send_motion(touch->obj, time, id, x_w, y_w);
+ }
+}
+
+void
+waltham_touch_frame(struct window *window)
+{
+ struct seat *seat = window->receiver_seat;
+ struct touch *touch = seat->touch;
+
+ if (touch->obj) {
+ fprintf(stdout, "waltham_touch_frame() sending frame\n");
+ wthp_touch_send_frame(touch->obj);
+ }
+}
+
+void
+waltham_touch_cancel(struct window *window)
+{
+ struct seat *seat = window->receiver_seat;
+ struct touch *touch = seat->touch;
+
+ if (touch->obj) {
+ fprintf(stdout, "waltham_touch_cancel() sending cancel\n");
+ wthp_touch_send_cancel(touch->obj);
+ }
+}
+
+/*
+ * APIs to send pointer events to waltham client
+ */
+
+void
+waltham_pointer_enter(struct window *window, uint32_t serial,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ struct surface *surface = window->receiver_surf;
+ struct seat *seat = window->receiver_seat;
+ struct pointer *pointer = seat->pointer;
+
+ if (pointer->obj) {
+ fprintf(stdout, "waltham_pointer_enter() sending enter\n");
+ wthp_pointer_send_enter(pointer->obj, serial, surface->obj, sx, sy);
+ }
+}
+
+void
+waltham_pointer_leave(struct window *window, uint32_t serial)
+{
+ struct surface *surface = window->receiver_surf;
+ struct seat *seat = window->receiver_seat;
+ struct pointer *pointer = seat->pointer;
+
+ if (pointer->obj) {
+ fprintf(stdout, "waltham_pointer_leave() sending leave\n");
+ wthp_pointer_send_leave(pointer->obj, serial, surface->obj);
+ }
+}
+
+void
+waltham_pointer_motion(struct window *window, uint32_t time,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ struct seat *seat = window->receiver_seat;
+ struct pointer *pointer = seat->pointer;
+
+ if (pointer->obj) {
+ fprintf(stdout, "waltham_pointer_motion() sending motion\n");
+ wthp_pointer_send_motion(pointer->obj, time, sx, sy);
+ }
+}
+
+void
+waltham_pointer_button(struct window *window, uint32_t serial,
+ uint32_t time, uint32_t button,
+ uint32_t state)
+{
+ struct seat *seat = window->receiver_seat;
+ struct pointer *pointer = seat->pointer;
+
+ if (pointer->obj) {
+ fprintf(stdout, "waltham_pointer_button() sending button\n");
+ wthp_pointer_send_button(pointer->obj, serial, time, button, state);
+ }
+}
+
+void
+waltham_pointer_axis(struct window *window, uint32_t time,
+ uint32_t axis, wl_fixed_t value)
+{
+ struct seat *seat = window->receiver_seat;
+ struct pointer *pointer = seat->pointer;
+
+ if (pointer->obj) {
+ fprintf(stdout, "waltham_pointer_axis() sending pointer_axis\n");
+ wthp_pointer_send_axis(pointer->obj, time, axis, value);
+ }
+}
+
+/*
+ * waltham seat implementation
+ */
+
+/*
+ * waltham touch implementation
+ */
+static void
+touch_release(struct wthp_touch *wthp_touch)
+{
+ struct touch *touch = wth_object_get_user_data((struct wth_object *)wthp_touch);
+ fprintf(stdout, "touch_release %p touch %p\n", wthp_touch, touch);
+}
+
+static const struct wthp_touch_interface touch_implementation = {
+ touch_release,
+};
+
+/*
+ * waltham pointer implementation
+ */
+static void
+pointer_set_cursor(struct wthp_pointer *wthp_pointer, uint32_t serial, struct wthp_surface *surface,
+ int32_t hotspot_x, int32_t hotspot_y)
+{
+}
+
+static void
+pointer_release(struct wthp_pointer *wthp_pointer)
+{
+}
+
+static const struct wthp_pointer_interface pointer_implementation = {
+ pointer_set_cursor,
+ pointer_release
+};
+
+static void
+seat_get_pointer(struct wthp_seat *wthp_seat, struct wthp_pointer *wthp_pointer)
+{
+
+ fprintf(stdout, "wthp_seat %p get_pointer(%p)\n", wthp_seat, wthp_pointer);
+
+ struct seat *seat = wth_object_get_user_data((struct wth_object *)wthp_seat);
+ struct pointer *pointer;
+
+ pointer = zalloc(sizeof *pointer);
+ if (!pointer) {
+ client_post_out_of_memory(seat->client);
+ return;
+ }
+
+ pointer->obj = wthp_pointer;
+ pointer->seat = seat;
+ seat->pointer = pointer;
+ wl_list_insert(&seat->client->pointer_list, &pointer->link);
+
+ wthp_pointer_set_interface(wthp_pointer, &pointer_implementation, pointer);
+
+}
+
+static void
+seat_get_touch(struct wthp_seat *wthp_seat, struct wthp_touch *wthp_touch)
+{
+ struct seat *seat = wth_object_get_user_data((struct wth_object *)wthp_seat);
+ struct touch *touch;
+
+ fprintf(stdout, "wthp_seat %p get_touch(%p)\n", wthp_seat, wthp_touch);
+
+ touch = zalloc(sizeof(*touch));
+ if (!touch) {
+ client_post_out_of_memory(seat->client);
+ return;
+ }
+
+ touch->obj = wthp_touch;
+ touch->seat = seat;
+
+ seat->touch = touch;
+
+ fprintf(stdout, "seat_get_touch() with obj %p\n", touch->obj);
+
+ wl_list_insert(&seat->client->touch_list, &touch->link);
+ wthp_touch_set_interface(wthp_touch, &touch_implementation, touch);
+}
+
+static void
+seat_get_keyboard(struct wthp_seat *wthp_seat, struct wthp_keyboard *kid)
+{
+ (void) wthp_seat;
+ (void) kid;
+}
+
+static void
+seat_release(struct wthp_seat *wthp_seat)
+{
+
+}
+
+static const struct wthp_seat_interface seat_implementation = {
+ seat_get_pointer,
+ seat_get_keyboard,
+ seat_get_touch,
+ seat_release,
+};
+
+void
+seat_send_updated_caps(struct seat *seat)
+{
+ enum wthp_seat_capability caps = 0;
+
+ caps |= WTHP_SEAT_CAPABILITY_POINTER;
+ fprintf(stdout, "WTHP_SEAT_CAPABILITY_POINTER %d\n", caps);
+
+ caps |= WTHP_SEAT_CAPABILITY_TOUCH;
+ fprintf(stdout, "WTHP_SEAT_CAPABILITY_TOUCH %d\n", caps);
+
+ wthp_seat_send_capabilities(seat->obj, caps);
+}
+
+void
+client_bind_seat(struct client *c, struct wthp_seat *obj)
+{
+ struct seat *seat;
+
+ seat = zalloc(sizeof *seat);
+ if (!seat) {
+ client_post_out_of_memory(c);
+ return;
+ }
+
+ seat->obj = obj;
+ seat->client = c;
+ wl_list_insert(&c->seat_list, &seat->link);
+
+ fprintf(stdout, "wthp_seat object=%p and seat=%p\n",obj,seat);
+ wthp_seat_set_interface(obj, &seat_implementation, seat);
+
+ fprintf(stdout, "client %p bound wthp_seat\n", c);
+ seat_send_updated_caps(seat);
+}
diff --git a/src/wth-receiver-surface.c b/src/wth-receiver-surface.c
new file mode 100644
index 0000000..ec89677
--- /dev/null
+++ b/src/wth-receiver-surface.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright © 2019 Advanced Driver Information Technology GmbH
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "wth-receiver-comm.h"
+#include "wth-receiver-buffer.h"
+#include "wth-receiver-seat.h"
+#include "wth-receiver-surface.h"
+
+void
+wth_receiver_weston_shm_attach(struct window *window, uint32_t data_sz, void * data,
+ int32_t width, int32_t height, int32_t stride, uint32_t format)
+{
+ /* stub */
+}
+
+void
+wth_receiver_weston_shm_damage(struct window *window)
+{
+ /* stub */
+}
+
+void
+wth_receiver_weston_shm_commit(struct window *window)
+{
+ /* stub */
+}
+
+/*
+ * waltham surface implementation
+ */
+void
+surface_destroy(struct surface *surface)
+{
+ wthp_surface_free(surface->obj);
+ wl_list_remove(&surface->link);
+ free(surface);
+}
+
+static void
+surface_handle_destroy(struct wthp_surface *wthp_surface)
+{
+ struct surface *surface = wth_object_get_user_data((struct wth_object *)wthp_surface);
+
+ assert(wthp_surface == surface->obj);
+ surface_destroy(surface);
+}
+
+static void
+surface_handle_attach(struct wthp_surface *wthp_surface,
+ struct wthp_buffer *wthp_buff, int32_t x, int32_t y)
+{
+ struct surface *surf = wth_object_get_user_data((struct wth_object *)wthp_surface);
+ struct buffer *buf = container_of(&wthp_buff, struct buffer, obj);
+
+ if (surf->ivi_id != 0) {
+ wth_receiver_weston_shm_attach(surf->shm_window,
+ buf->data_sz,
+ buf->data,
+ buf->width,
+ buf->height,
+ buf->stride,
+ buf->format);
+
+ wthp_buffer_send_complete(wthp_buff, 0);
+ }
+}
+
+static void
+surface_handle_damage(struct wthp_surface *wthp_surface,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ struct surface *surf = wth_object_get_user_data((struct wth_object *)wthp_surface);
+
+ if (surf->ivi_id != 0) {
+ wth_receiver_weston_shm_damage(surf->shm_window);
+ }
+}
+
+static void
+surface_handle_frame(struct wthp_surface *wthp_surface,
+ struct wthp_callback *callback)
+{
+ struct surface *surf = wth_object_get_user_data((struct wth_object *)wthp_surface);
+ surf->cb = callback;
+}
+
+static void
+surface_handle_set_opaque_region(struct wthp_surface *wthp_surface,
+ struct wthp_region *region)
+{
+
+}
+
+static void
+surface_handle_set_input_region(struct wthp_surface *wthp_surface,
+ struct wthp_region *region)
+{
+
+}
+
+static void
+surface_handle_commit(struct wthp_surface *wthp_surface)
+{
+ struct surface *surf = wth_object_get_user_data((struct wth_object *)wthp_surface);
+
+ if (surf->ivi_id != 0) {
+ wth_receiver_weston_shm_commit(surf->shm_window);
+ }
+}
+
+static void
+surface_handle_set_buffer_transform(struct wthp_surface *wthp_surface,
+ int32_t transform)
+{
+
+}
+
+static void
+surface_handle_set_buffer_scale(struct wthp_surface *wthp_surface,
+ int32_t scale)
+{
+
+}
+
+static void
+surface_handle_damage_buffer(struct wthp_surface *wthp_surface,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+
+}
+
+static const struct wthp_surface_interface surface_implementation = {
+ surface_handle_destroy,
+ surface_handle_attach,
+ surface_handle_damage,
+ surface_handle_frame,
+ surface_handle_set_opaque_region,
+ surface_handle_set_input_region,
+ surface_handle_commit,
+ surface_handle_set_buffer_transform,
+ surface_handle_set_buffer_scale,
+ surface_handle_damage_buffer
+};
+
+static void
+compositor_handle_create_surface(struct wthp_compositor *compositor,
+ struct wthp_surface *id)
+{
+
+ struct compositor *comp = wth_object_get_user_data((struct wth_object *)compositor);
+ struct client *client = comp->client;
+ struct surface *surface;
+ struct seat *seat, *tmp;
+
+ surface = zalloc(sizeof *surface);
+ if (!surface) {
+ client_post_out_of_memory(comp->client);
+ return;
+ }
+
+ surface->obj = id;
+ wl_list_insert(&comp->client->surface_list, &surface->link);
+
+ wthp_surface_set_interface(id, &surface_implementation, surface);
+
+ surface->shm_window = calloc(1, sizeof *surface->shm_window);
+ if (!surface->shm_window)
+ return;
+
+ surface->shm_window->receiver_surf = surface;
+ surface->shm_window->ready = false;
+ surface->ivi_id = 0;
+
+ wl_list_for_each_safe(seat, tmp, &client->seat_list, link) {
+ surface->shm_window->receiver_seat = seat;
+ }
+}
+
+/*
+ * waltham region implementation
+ */
+void
+region_destroy(struct region *region)
+{
+ wthp_region_free(region->obj);
+ wl_list_remove(&region->link);
+ free(region);
+}
+
+static void
+region_handle_destroy(struct wthp_region *wthp_region)
+{
+ struct region *region = wth_object_get_user_data((struct wth_object *)wthp_region);
+ assert(wthp_region == region->obj);
+ region_destroy(region);
+}
+
+static void
+region_handle_add(struct wthp_region *wthp_region,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+}
+
+static void
+region_handle_subtract(struct wthp_region *wthp_region,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+}
+
+static const struct wthp_region_interface region_implementation = {
+ region_handle_destroy,
+ region_handle_add,
+ region_handle_subtract
+};
+
+/*
+ * waltham compositor implementation
+ */
+void
+compositor_destroy(struct compositor *comp)
+{
+ wthp_compositor_free(comp->obj);
+ wl_list_remove(&comp->link);
+ free(comp);
+}
+
+static void
+compositor_handle_create_region(struct wthp_compositor *compositor,
+ struct wthp_region *id)
+{
+ struct compositor *comp = wth_object_get_user_data((struct wth_object *)compositor);
+ struct region *region;
+
+ region = zalloc(sizeof *region);
+ if (!region) {
+ client_post_out_of_memory(comp->client);
+ return;
+ }
+
+ region->obj = id;
+ wl_list_insert(&comp->client->region_list, &region->link);
+
+ wthp_region_set_interface(id, &region_implementation, region);
+}
+
+static const struct wthp_compositor_interface compositor_implementation = {
+ compositor_handle_create_surface,
+ compositor_handle_create_region
+};
+
+void
+client_bind_compositor(struct client *c, struct wthp_compositor *obj)
+{
+
+ struct compositor *comp;
+
+ comp = zalloc(sizeof *comp);
+ if (!comp) {
+ client_post_out_of_memory(c);
+ return;
+ }
+
+ comp->obj = obj;
+ comp->client = c;
+ wl_list_insert(&c->compositor_list, &comp->link);
+
+ wthp_compositor_set_interface(obj, &compositor_implementation, comp);
+}