summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--COPYING30
-rw-r--r--README.md125
-rw-r--r--attic/waltham-renderer/meson.build27
-rw-r--r--attic/waltham-renderer/pipeline_example_general.cfg1
-rw-r--r--attic/waltham-renderer/pipeline_example_intel.cfg1
-rw-r--r--attic/waltham-renderer/pipeline_example_rcar.cfg1
-rw-r--r--attic/waltham-renderer/waltham-renderer.c281
-rw-r--r--include/meson.build4
-rw-r--r--include/plugin.h333
-rw-r--r--include/transmitter_api.h283
-rw-r--r--include/waltham-renderer.h43
-rw-r--r--meson.build58
-rw-r--r--transmitter-plugin/input.c1333
-rw-r--r--transmitter-plugin/meson.build24
-rw-r--r--transmitter-plugin/output.c57
-rw-r--r--transmitter-plugin/plugin.c1024
-rw-r--r--transmitter-plugin/weston.ini.transmitter13
17 files changed, 3638 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d65f5d3
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,30 @@
+Copyright © 2008-2012 Kristian Høgsberg
+Copyright © 2010-2012 Intel Corporation
+Copyright © 2010-2011 Benjamin Franzke
+Copyright © 2011-2012 Collabora, Ltd.
+Copyright © 2010 Red Hat <mjg@redhat.com>
+
+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.
+
+---
+
+The above is the version of the MIT "Expat" License used by X.org:
+
+ http://cgit.freedesktop.org/xorg/xserver/tree/COPYING
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..25b54ad
--- /dev/null
+++ b/README.md
@@ -0,0 +1,125 @@
+# Waltham Transmitter #
+
+Waltham transmitter is a weston plugin which uses waltham IPC library to
+connect to remote and transmit input events from the remote client back
+to the compositor.
+
+Transmitter plugin provides the API to create remote connections and push
+surfaces over the network and handles remote input. The remote output creation
+and handling is being done by the remoting plug-in.
+
+
+### Architecture
+
+````
+ ECU 1 ECU 2
+ +-----------------------------------------------------+ +----------------------------------------------+
+ | +-----------------+ | | |
+ | | IVI-Application | | | +-----------+-----------+ |
+ | +-----------------+ | | | Gstreamer | | |
+ | ^ | Buffer -----------------------> (Decode) | | |
+ | wayland | +----------------------/ | +-----------+ | |
+ | v | | (Ethernet) | | Waltham-receiver | |
+ | +----+---------------------+ | | ----------------------------> | |
+ | | | Transmitter Plugin |<-----------------------------/ | +-----------------------+ |
+ | | | | | | Waltham-Protocol | ^ |
+ | | |---------------------+ | | | wayland | |
+ | | | Remoting plug-in |------------+ | | v |
+ | | | | | | +---------------------+ |
+ | | +-+-------------------+ | | | | |
+ | | | | | | compositor | |
+ | | compositor | | | | | |
+ | +------+-------------------+ | | +----------------+----+ |
+ | | | | | |
+ | v | | v |
+ | +------------+ | | +----------+ |
+ | | Display | | | | Display | |
+ | | | | | | | |
+ | +------------+ | | +----------+ |
+ +-----------------------------------------------------+ +----------------------------------------------+
+
+````
+
+### How to build
+
+1. Prerequisite before building
+
+ weston, wayland, gstreamer plugins and waltham should be built and
+ available.
+
+2. Get the source code from the repository.
+
+ $ git clone https://gerrit.automotivelinux.org/gerrit/src/waltham-transmitter
+
+3. Create build folder
+
+ $ cd waltham-transmitter
+ $ meson -Dprefix=$PREFIX_PATH build/
+
+4. Run ninja
+
+ $ ninja -C build/ install
+
+5. waltham-transmitter.so should be available in the
+ $PREFIX_PATH/lib/x86_64-linux-gnu/libweston-$MAJOR
+
+### How to configure the compositor and gstreamer pipeline
+
+1. weston.ini:
+
+The transmitter plugin will be loaded automatically is found in the plug-ins
+directory of weston.
+
+The destination of remoting output is configured in weston.ini and it matches
+the key entries from the remoting plug-in -- the output being actually created
+by the remoting plug-in. Add output name, server address, mode ini entries
+under '[transmitter-output]'. You can specify multiple [transmitter-output].
+
+You can specify which application to be started/placed on the remote output
+by adding agl-shell-app-id=app_id_name.
+
+2. gstreamer pipeline:
+
+You can customize the gstreamer pipeline as you want by configuring the
+pipeline entry.
+
+Some pipeline gstreamer examples are in the following files:
+
+- pipeline_example_general.cfg : Does not use any HW encoder.
+- pipeline_example_intel.cfg : Use Intel's HW encoder.
+- pipeline_example_rcar.cfg : Use Rcar's HW encoder.
+
+### 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. The section is
+ identical to that of the remoting plug-in, only the name of the section is
+ different.
+
+### How to test
+
+Start the compositor with modified weston.ini mention above. You can confirm
+the transmitter is loaded properly from weston log as below.
+
+````
+[07:14:23.032] Transmitter weston_seat 0xaaaad0079e50
+[07:14:23.032] Transmitter created pointer=0xaaaad00977c0 for seat 0xaaaad0079e50
+[07:14:23.032] Transmitter created keyboard=0xaaaad0079fe0 for seat 0xaaaad0079e50
+[07:14:23.032] Transmitter created touch=0xaaaacffe1010 for seat 0xaaaad0079e50
+````
+
+Start remoting:
+
+- Start the remote compositor and start the receiver application.
+- Start the compositor on the transmitter side and the application mentioned in
+'[transmitter-output]' section, under agl-shell-app-id in order to 'forward'
+the application to that output.
diff --git a/attic/waltham-renderer/meson.build b/attic/waltham-renderer/meson.build
new file mode 100644
index 0000000..9754bc9
--- /dev/null
+++ b/attic/waltham-renderer/meson.build
@@ -0,0 +1,27 @@
+
+libpixman_dep = dependency('pixman-1')
+dep_gstreamer = dependency('gstreamer-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')
+
+deps_renderer_plugin = [
+ libwayland_dep,
+ libpixman_dep,
+ libweston_dep,
+ libwaltham_dep,
+ weston_dep,
+ dep_gstreamer, dep_gstreamer_app,
+ dep_gstreamer_video, dep_gstreamer_alloc
+]
+
+plugin_renderer = shared_library(
+ 'waltham-renderer',
+ 'waltham-renderer.c',
+ include_directories: common_inc,
+ dependencies: deps_renderer_plugin,
+ name_prefix: '',
+ install: true,
+ install_dir: plugin_install_dir,
+)
+env_modmap += 'renderer-plugin.so=@0@;'.format(plugin_renderer.full_path())
diff --git a/attic/waltham-renderer/pipeline_example_general.cfg b/attic/waltham-renderer/pipeline_example_general.cfg
new file mode 100644
index 0000000..31db32e
--- /dev/null
+++ b/attic/waltham-renderer/pipeline_example_general.cfg
@@ -0,0 +1 @@
+appsrc name=src ! videoconvert ! video/x-raw,format=I420 ! jpegenc ! rtpjpegpay ! udpsink name=sink host=YOUR_RECIEVER_IP port=YOUR_RECIEVER_PORT sync=false async=false \ No newline at end of file
diff --git a/attic/waltham-renderer/pipeline_example_intel.cfg b/attic/waltham-renderer/pipeline_example_intel.cfg
new file mode 100644
index 0000000..8440bce
--- /dev/null
+++ b/attic/waltham-renderer/pipeline_example_intel.cfg
@@ -0,0 +1 @@
+appsrc name=src ! videoconvert ! video/x-raw,format=I420 ! mfxh264enc bitrate=3000000 rate-control=1 ! rtph264pay config-interval=1 ! udpsink name=sink host=YOUR_RECIEVER_IP port=YOUR_RECIEVER_PORT sync=false async=false \ No newline at end of file
diff --git a/attic/waltham-renderer/pipeline_example_rcar.cfg b/attic/waltham-renderer/pipeline_example_rcar.cfg
new file mode 100644
index 0000000..2993365
--- /dev/null
+++ b/attic/waltham-renderer/pipeline_example_rcar.cfg
@@ -0,0 +1 @@
+appsrc name=src ! videoconvert ! video/x-raw,format=I420 ! omxh264enc bitrate=3000000 control-rate=2 ! rtph264pay ! udpsink name=sink host=YOUR_RECIEVER_IP port=YOUR_RECIEVER_PORT sync=false async=false \ No newline at end of file
diff --git a/attic/waltham-renderer/waltham-renderer.c b/attic/waltham-renderer/waltham-renderer.c
new file mode 100644
index 0000000..cda354e
--- /dev/null
+++ b/attic/waltham-renderer/waltham-renderer.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2017 Advanced Driver Information Technology GmbH, Robert Bosch GmbH, Robert Bosch Car Multimedia GmbH, DENSO Corporation
+ *
+ * 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 <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <gst/gst.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/allocators/gstdmabuf.h>
+#include <gst/app/gstappsrc.h>
+
+#include <libweston/libweston.h>
+
+#include "transmitter_api.h"
+#include "waltham-renderer.h"
+#include "plugin.h"
+
+struct waltham_renderer {
+ struct renderer base;
+};
+
+struct GstAppContext {
+ GMainLoop *loop;
+ GstBus *bus;
+ GstElement *pipeline;
+ GstElement *appsrc;
+ GstBuffer *gstbuffer;
+};
+
+gboolean bus_message(GstBus *bus, GstMessage *message, gpointer p)
+{
+ struct GstAppContext *gstctx = p;
+
+ switch( GST_MESSAGE_TYPE(message)) {
+ case GST_MESSAGE_ERROR:
+ {
+ GError *err;
+ gchar *debug;
+
+ gst_message_parse_error(message, &err, &debug);
+ g_print("ERROR: %s\n", err->message);
+
+ g_error_free(err);
+ g_free(debug);
+ g_main_loop_quit(gstctx->loop);
+
+ return false;
+ break;
+ }
+
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ GstState oldstate, newstate;
+
+ gst_message_parse_state_changed(message, &oldstate, &newstate, NULL);
+ switch (newstate){
+ case GST_STATE_PAUSED:
+ fprintf(stderr, "%s: state is paused\n", GST_MESSAGE_SRC_NAME(message));
+ break;
+ case GST_STATE_READY:
+ fprintf(stderr, "%s: state is ready\n", GST_MESSAGE_SRC_NAME(message));
+ break;
+ case GST_STATE_VOID_PENDING:
+ fprintf(stderr, "%s: state is pending\n", GST_MESSAGE_SRC_NAME(message));
+ break;
+ case GST_STATE_NULL:
+ fprintf(stderr, "%s: state is NULL\n", GST_MESSAGE_SRC_NAME(message));
+ break;
+ case GST_STATE_PLAYING:
+ fprintf(stderr, "%s: state is playing\n", GST_MESSAGE_SRC_NAME(message));
+ break;
+ }
+ break;
+ }
+ default:
+ fprintf(stderr, "Unhandled message\n");
+ break;
+ }
+
+ return true;
+}
+
+static int
+gst_pipe_init(struct weston_transmitter_output *output, struct gst_settings *settings)
+{
+ struct GstAppContext *gstctx;
+ GstCaps *caps;
+ GError *gerror = NULL;
+ FILE * pFile;
+ size_t lSize;
+ char * pipe = NULL;
+ size_t res;
+
+ gstctx=zalloc(sizeof (*gstctx));
+ if(!gstctx){
+ weston_log("Enable to allocate memory\n");
+ return -1;
+ }
+
+ /* create gstreamer pipeline */
+ gst_init(NULL, NULL);
+ gstctx->loop = g_main_loop_new(NULL, FALSE);
+
+ /* read pipeline from file */
+ pFile = fopen("/etc/xdg/weston/transmitter_pipeline.cfg" , "rb");
+ if (pFile==NULL) {
+ weston_log("File open error\n");
+ return -1;
+ }
+
+ /* obtain file size */
+ fseek (pFile , 0 , SEEK_END);
+ lSize = ftell (pFile);
+ rewind (pFile);
+
+ /* allocate memory to contain the whole file: */
+ pipe = zalloc (sizeof(char) * lSize);
+ if (pipe == NULL) {
+ weston_log("Cannot allocate memory\n");
+ return -1;
+ }
+
+ /* copy the file into the buffer: */
+ res = fread (pipe,1,lSize,pFile);
+ if (res != lSize)
+ {
+ weston_log("File read error\n");
+ return -1;
+ }
+
+ /* close file */
+ fclose(pFile);
+ weston_log("Parsing GST pipeline:%s",pipe);
+ gstctx->pipeline = gst_parse_launch(pipe, &gerror);
+ free(pipe);
+ if(!gstctx->pipeline)
+ weston_log("Could not create gstreamer pipeline.\n");
+
+ gstctx->bus = gst_pipeline_get_bus((GstPipeline*)((void*)gstctx->pipeline));
+ gst_bus_add_watch(gstctx->bus, bus_message, &gstctx);
+
+ //gstctx->appsrc = (GstAppSrc*) gst_bin_get_by_name(GST_BIN(gstctx->pipeline), "src");
+ gstctx->appsrc = gst_bin_get_by_name(GST_BIN(gstctx->pipeline), "src");
+ if (!gstctx->appsrc)
+ return -1;
+
+ caps = gst_caps_new_simple("video/x-raw",
+ "format", G_TYPE_STRING, "BGRx",
+ "width", G_TYPE_INT, settings->width,
+ "height", G_TYPE_INT, settings->height,
+ NULL);
+ if (!caps)
+ return -1;
+
+ g_object_set(G_OBJECT(gstctx->appsrc),
+ "caps", caps,
+ "stream-type", 0,
+ "format", GST_FORMAT_TIME,
+ "is-live", TRUE,
+ NULL);
+ gst_caps_unref(caps);
+
+ gst_element_set_state((GstElement*)((void*)gstctx->pipeline), GST_STATE_PLAYING);
+ output->renderer->ctx = gstctx;
+
+ weston_log("Gstreamer pipeline inited\n");
+
+ return 0;
+}
+
+static int
+recorder_enable(struct weston_transmitter_output *output)
+{
+ struct gst_settings *settings;
+
+ struct weston_transmitter_remote* remote = output->remote;
+
+ /*
+ * Limitation:
+ * Hard coding bitrate and crop params.
+ * In case of gst-recorder case these were taken from weston.ini
+ */
+ int32_t bitrate = 3000000;
+
+ settings = malloc(sizeof(* settings));
+ settings->ip = remote->addr;
+
+ settings->port = atoi(remote->port);
+
+ settings->bitrate = bitrate;
+ settings->width = output->renderer->surface_width;
+ settings->height = output->renderer->surface_height;
+
+ weston_log("gst-setting are :-->\n");
+ weston_log("ip = %s \n",settings->ip);
+ weston_log("port = %d \n",settings->port);
+ weston_log("bitrate = %d \n",settings->bitrate);
+ weston_log("width = %d \n",settings->width);
+ weston_log("height = %d \n",settings->height);
+
+ gst_pipe_init(output, settings);
+
+ weston_log("Enabling renderer display\n");
+
+ return 0;
+}
+
+static void waltham_renderer_repaint_output(struct weston_transmitter_output *output)
+{
+ GstBuffer *gstbuffer;
+ GstMemory *mem;
+ GstAllocator *allocator;
+ int stride = output->renderer->buf_stride;
+ gsize offset = 0;
+
+ if (!output->renderer->recorder_enabled) {
+ recorder_enable(output);
+ output->renderer->recorder_enabled = 1;
+ }
+
+ gstbuffer = gst_buffer_new();
+ allocator = gst_dmabuf_allocator_new();
+ mem = gst_dmabuf_allocator_alloc(allocator, output->renderer->dmafd,
+ stride * output->renderer->surface_height);
+ gst_buffer_append_memory(gstbuffer, mem);
+ gst_buffer_add_video_meta_full(gstbuffer,
+ GST_VIDEO_FRAME_FLAG_NONE,
+ GST_VIDEO_FORMAT_BGRx,
+ output->renderer->surface_width,
+ output->renderer->surface_height,
+ 1,
+ &offset,
+ &stride);
+
+ gst_app_src_push_buffer(GST_APP_SRC(output->renderer->ctx->appsrc), gstbuffer);
+ gst_object_unref(allocator);
+}
+
+static int
+waltham_renderer_display_create(struct weston_transmitter_output *output)
+{
+ struct waltham_renderer *wth_renderer;
+
+ wth_renderer = zalloc(sizeof *wth_renderer);
+ if (wth_renderer == NULL)
+ return -1;
+
+ wth_renderer->base.repaint_output = waltham_renderer_repaint_output;
+ output->renderer = &wth_renderer->base;
+
+ weston_log("Created renderer display\n");
+
+ return 0;
+}
+
+WL_EXPORT struct waltham_renderer_interface waltham_renderer_interface = {
+ .display_create = waltham_renderer_display_create
+};
diff --git a/include/meson.build b/include/meson.build
new file mode 100644
index 0000000..a8c2855
--- /dev/null
+++ b/include/meson.build
@@ -0,0 +1,4 @@
+install_headers(
+ 'transmitter_api.h',
+ subdir: dir_include_waltham_transmiter_install
+)
diff --git a/include/plugin.h b/include/plugin.h
new file mode 100644
index 0000000..daa0fea
--- /dev/null
+++ b/include/plugin.h
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2017 Advanced Driver Information Technology Joint Venture 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.
+ */
+
+#ifndef WESTON_TRANSMITTER_PLUGIN_H
+#define WESTON_TRANSMITTER_PLUGIN_H
+
+/* XXX: all functions and variables with a name, and things marked with a
+ * comment, containing the word "fake" are mockups that need to be
+ * removed from the final implementation.
+ */
+
+#include <stdint.h>
+#include <wayland-client.h>
+
+#include <libweston/libweston.h>
+#include <ivi-layout-export.h>
+
+#include "transmitter_api.h"
+
+#include <waltham-client.h>
+
+
+struct waltham_display;
+
+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,
+};
+
+/* epoll structure */
+struct watch {
+ struct waltham_display *display;
+ int fd;
+ void (*cb)(struct watch *w, uint32_t events);
+};
+
+struct waltham_display {
+ struct wth_connection *connection;
+ struct watch conn_watch;
+ struct wth_display *display;
+
+ bool running;
+
+ struct wthp_registry *registry;
+
+ struct wthp_callback *bling;
+
+ struct wthp_compositor *compositor;
+ struct wthp_blob_factory *blob_factory;
+ struct wthp_seat *seat;
+ struct wthp_pointer *pointer;
+ struct wthp_keyboard *keyboard;
+ struct wthp_touch *touch;
+ struct wthp_ivi_application *application;
+ struct wthp_ivi_app_id *application_id;
+ struct wtimer *fiddle_timer;
+
+ struct weston_transmitter_remote *remote;
+ char *addr;
+ char *port;
+};
+
+/* a timerfd based timer */
+struct wtimer {
+ struct watch watch;
+ void (*func)(struct wtimer *, void *);
+ void *data;
+};
+
+struct weston_transmitter {
+ struct weston_compositor *compositor;
+ struct wl_listener compositor_destroy_listener;
+
+ struct wl_list remote_list; /* transmitter_remote::link */
+
+ struct wl_listener stream_listener;
+ struct wl_signal connected_signal;
+ struct wl_event_loop *loop;
+
+ struct waltham_renderer_interface *waltham_renderer;
+};
+
+struct weston_transmitter_remote {
+ struct weston_transmitter *transmitter;
+ struct wl_list link;
+ char *model;
+ char *addr;
+ char *port;
+ int32_t width;
+ int32_t height;
+
+ enum weston_transmitter_connection_status status;
+ struct wl_signal connection_status_signal;
+ struct wl_signal conn_establish_signal;
+
+ struct wl_list output_list; /* weston_transmitter_output::link */
+ struct wl_list surface_list; /* weston_transmitter_surface::link */
+ struct wl_list seat_list; /* weston_transmitter_seat::link */
+
+ struct wl_listener establish_listener;
+
+ struct wl_event_source *establish_timer; /* for establish connection */
+ struct wl_event_source *retry_timer; /* for retry connection */
+
+ struct waltham_display *display; /* waltham */
+ struct wl_event_source *source;
+};
+
+
+struct weston_transmitter_surface {
+ struct weston_transmitter_remote *remote;
+ struct wl_list link; /* weston_transmitter_remote::surface_list */
+ struct wl_signal destroy_signal; /* data: weston_transmitter_surface */
+
+ enum weston_transmitter_stream_status status;
+ struct wl_signal stream_status_signal;
+
+ struct weston_surface *surface;
+ struct wl_listener surface_destroy_listener;
+ const struct ivi_layout_interface *lyt; /* not needed anymore, please remove */
+
+ weston_transmitter_ivi_resize_handler_t resize_handler;
+ void *resize_handler_data;
+
+ struct weston_output *sync_output;
+ struct wl_listener sync_output_destroy_listener;
+
+ int32_t attach_dx; /**< wl_surface.attach(buffer, dx, dy) */
+ int32_t attach_dy; /**< wl_surface.attach(buffer, dx, dy) */
+ struct wl_list frame_callback_list; /* weston_frame_callback::link */
+ struct wl_list feedback_list; /* weston_presentation_feedback::link */
+
+ /* waltham */
+ struct wthp_surface *wthp_surf;
+ struct wthp_blob_factory *wthp_blob;
+ struct wthp_buffer *wthp_buf;
+ struct wthp_ivi_surface *wthp_ivi_surface;
+ struct wthp_ivi_application *wthp_ivi_application;
+};
+
+struct weston_transmitter_output_info {
+ uint32_t subpixel; /* enum wl_output_subpixel */
+ uint32_t transform; /* enum wl_output_transform */
+ int32_t scale;
+ int32_t x;
+ int32_t y;
+ int32_t width_mm;
+ int32_t height_mm;
+ /* char *make; is WESTON_TRANSMITTER_OUTPUT_MAKE */
+ char *model;
+
+ struct weston_mode mode;
+};
+
+struct weston_transmitter_output {
+ struct weston_output base;
+
+ struct {
+ bool draw_initial_frame;
+ struct wl_surface *surface;
+ struct wl_output *output;
+ struct wl_display *display;
+ int configure_width, configure_height;
+ bool wait_for_configure;
+ } parent;
+
+ const char *name;
+ struct weston_transmitter_remote *remote;
+ struct wl_list link; /* weston_transmitter_remote::output_list */
+
+ struct frame *frame;
+ struct wl_event_source *finish_frame_timer;
+ struct wl_callback *frame_cb;
+ struct renderer *renderer;
+};
+
+struct weston_transmitter_seat {
+ struct weston_seat *base;
+ struct wl_list link;
+
+ /* pointer */
+ wl_fixed_t pointer_surface_x;
+ wl_fixed_t pointer_surface_y;
+
+ struct wl_listener get_pointer_listener;
+ struct weston_transmitter_surface *pointer_focus;
+ struct wl_listener pointer_focus_destroy_listener;
+
+ struct wl_event_source *pointer_timer; /* fake */
+
+ double pointer_phase; /* fake */
+
+ /* keyboard */
+ struct weston_transmitter_surface *keyboard_focus;
+
+ /* touch */
+ struct weston_transmitter_surface *touch_focus;
+};
+
+struct ivi_layout_surface {
+ struct wl_list link; /* ivi_layout::surface_list */
+ struct wl_signal property_changed;
+ int32_t update_count;
+ uint32_t id_surface;
+
+ struct ivi_layout *layout;
+ struct weston_surface *surface;
+
+ struct ivi_layout_surface_properties prop;
+
+ struct {
+ struct ivi_layout_surface_properties prop;
+ } pending;
+
+ struct wl_list view_list; /* ivi_layout_view::surf_link */
+};
+
+void
+transmitter_surface_ivi_resize(struct weston_transmitter_surface *txs,
+ int32_t width, int32_t height);
+
+int
+transmitter_remote_create_output(struct weston_transmitter_remote *remote,
+ const struct weston_transmitter_output_info *info);
+int
+transmitter_remote_create_output_with_name(struct weston_transmitter_remote *remote, char *name);
+
+void
+transmitter_output_destroy(struct weston_transmitter_output *output);
+
+int
+transmitter_remote_create_seat(struct weston_transmitter_remote *remote);
+
+void
+transmitter_seat_destroy(struct weston_transmitter_seat *seat);
+
+/* The below are the functions to be called from the network protocol
+ * input event handlers.
+ */
+
+void
+transmitter_seat_pointer_enter(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y);
+
+void
+transmitter_seat_pointer_leave(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs);
+
+void
+transmitter_seat_pointer_motion(struct weston_transmitter_seat *seat,
+ uint32_t time,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y);
+
+void
+transmitter_seat_pointer_button(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t button,
+ uint32_t state);
+
+void
+transmitter_seat_pointer_axis(struct weston_transmitter_seat *seat,
+ uint32_t time,
+ uint32_t axis,
+ wl_fixed_t value);
+
+void
+transmitter_seat_pointer_frame(struct weston_transmitter_seat *seat);
+
+void
+transmitter_seat_pointer_axis_source(struct weston_transmitter_seat *seat,
+ uint32_t axis_source);
+
+void
+transmitter_seat_pointer_axis_stop(struct weston_transmitter_seat *seat,
+ uint32_t time,
+ uint32_t axis);
+
+void
+transmitter_seat_pointer_axis_discrete(struct weston_transmitter_seat *seat,
+ uint32_t axis,
+ int32_t discrete);
+
+/* Fake functions for mockup testing: */
+
+int
+transmitter_seat_fake_pointer_input(struct weston_transmitter_seat *seat,
+ struct weston_transmitter_surface *txs);
+
+void
+seat_capabilities(struct wthp_seat *wthp_seat,
+ enum wthp_seat_capability caps);
+
+
+
+#endif /* WESTON_TRANSMITTER_PLUGIN_H */
diff --git a/include/transmitter_api.h b/include/transmitter_api.h
new file mode 100644
index 0000000..39b616a
--- /dev/null
+++ b/include/transmitter_api.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2017 Advanced Driver Information Technology Joint Venture 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.
+ */
+
+#ifndef WESTON_TRANSMITTER_API_H
+#define WESTON_TRANSMITTER_API_H
+
+#include <libweston/plugin-registry.h>
+
+#include <stdint.h>
+
+/** \file
+ *
+ * This is the Transmitter API published via weston_plugin_api_register().
+ */
+
+struct weston_transmitter;
+struct weston_transmitter_remote;
+struct weston_transmitter_surface;
+struct weston_transmitter_output;
+
+#define WESTON_TRANSMITTER_API_NAME "transmitter_v1"
+
+/** See weston_transmitter_api::remote_get_status */
+enum weston_transmitter_connection_status {
+ /** The connection hand-shake is not yet complete */
+ WESTON_TRANSMITTER_CONNECTION_INITIALIZING,
+
+ /** The connection is live and ready to be used. */
+ WESTON_TRANSMITTER_CONNECTION_READY,
+
+ /** The connection is dead. */
+ WESTON_TRANSMITTER_CONNECTION_DISCONNECTED,
+};
+
+/** See weston_transmitter_api::surface_get_stream_status */
+enum weston_transmitter_stream_status {
+ /** The stream hand-shake is not yet complete. */
+ WESTON_TRANSMITTER_STREAM_INITIALIZING,
+
+ /** The stream is carrying surface content updates as needed. */
+ WESTON_TRANSMITTER_STREAM_LIVE,
+
+ /** The stream has failed and disconnected permanently. */
+ WESTON_TRANSMITTER_STREAM_FAILED,
+};
+
+/** The Transmitter Base API
+ *
+ * Transmitter is a Weston plugin that provides remoting of weston_surfaces
+ * over the network. Shells use this API to create remote connections and
+ * push surfaces over the network. Shells are also responsible for relaying
+ * basic window state changes to Transmitter.
+ *
+ * In addition to the Transmitter Base API, shells also need to use a
+ * shell protocol specific Transmitter API to relay specific window state
+ * changes.
+ */
+struct weston_transmitter_api {
+ /** Fetch the Transmitter plugin context
+ *
+ * \param compositor The compositor instance.
+ * \return The weston_transmitter context, which is always the same
+ * for the given compositor instance.
+ */
+ struct weston_transmitter *
+ (*transmitter_get)(struct weston_compositor *compositor);
+
+ /**
+ * Connect to a remote server via Transmitter.
+ *
+ * \param txr The Transmitter context.
+ * \param status Listener to inform of connection status changes.
+ * \return A handle to the remote connection, or NULL on failure.
+ *
+ * This call attempts to open a connection asynchronously. The
+ * connection is not usable until the listener signals it is ready.
+ * The listener may also signal that the connection failed instead.
+ *
+ * The listener callback argument is the weston_transmitter_remote
+ * returned by this function. Use remote_get_status() to fetch the
+ * current status.
+ *
+ */
+ struct weston_transmitter_remote *
+ (*connect_to_remote)(struct weston_transmitter *txr);
+
+ /**
+ * Retrieve the connection status.
+ *
+ * If the status is WESTON_TRANSMITTER_CONNECTION_DISCONNECTED,
+ * you have to shut the remote down completely. There is no automatic
+ * reconnect.
+ */
+ enum weston_transmitter_connection_status
+ (*remote_get_status)(struct weston_transmitter_remote *remote);
+
+ /**
+ * Destroy/disconnect a remote connection.
+ *
+ * Disconnects if connected, and destroys the connection.
+ * The connection status handler is not called.
+ *
+ * The caller is responsible for destroying all
+ * weston_transmitter_surfaces before calling this.
+ */
+ void
+ (*remote_destroy)(struct weston_transmitter_remote *remote);
+
+ /** Push a weston_surface to be transmitted to a remote.
+ *
+ * \param ws The surface to push.
+ * \param remote The remote connection to use.
+ * \param stream_status Listener for stream status changes.
+ * \return The Transmitter surface handle.
+ *
+ * The surface cannot be visible on the remote until the stream
+ * status listener signals WESTON_TRANSMITTER_STREAM_LIVE. After that,
+ * surface updates made by the application will be automatically
+ * streamed to the remote, and input events from the remote will be
+ * delivered to the application.
+ *
+ * The listener callback argument is the weston_transmitter_surface
+ * returned by this function. Use surface_get_stream_status() to
+ * fetch the current status.
+ */
+ struct weston_transmitter_surface *
+ (*surface_push_to_remote)(struct weston_surface *ws, const char *app_id,
+ struct weston_transmitter_remote *remote,
+ struct wl_listener *stream_status);
+
+ /**
+ * Retrieve the surface content stream status.
+ *
+ * If the status is WESTON_TRANSMITTER_STREAM_FAILED, remoting the
+ * surface has stopped. There is no automatic retry.
+ */
+ enum weston_transmitter_stream_status
+ (*surface_get_stream_status)(struct weston_transmitter_surface *txs);
+
+ /** Stop remoting a weston_surface
+ *
+ * \param txs Transmitter surface handle to be stopped and freed.
+ *
+ * The surface stream status handler is not called.
+ */
+ void
+ (*surface_destroy)(struct weston_transmitter_surface *txs);
+
+ /** Notify of weston_surface being configured
+ *
+ * \param txs The Transmitter surface handle.
+ * \param dx The x delta given in wl_surface.attach request.
+ * \param dy The y delta given in wl_surface.attach request.
+ *
+ * Notifies Transmitter of new surface confguration. Transmitter will
+ * forward the arguments, window state, and reference the buffer for
+ * image transmission.
+ *
+ * Shells are meant to call this function for remoted surfaces in
+ * the weston_surface::configure handler.
+ *
+ * XXX: Is this necessary if we have weston_surface::apply_state_signal?
+ *
+ * Essentially this is just an elaborate way to forward dx,dy.
+ */
+ void
+ (*surface_configure)(struct weston_transmitter_surface *txs,
+ int32_t dx, int32_t dy);
+
+ void
+ (*surface_gather_state)(struct weston_transmitter_surface *txs);
+
+ /** Notify that surface is connected to receiver
+ *
+ * \param txr The Transmitter context.
+ * \param connected_listener Listener for connected_signal.
+ */
+ void
+ (*register_connection_status)(struct weston_transmitter *txr,
+ struct wl_listener *connected_listener);
+
+ /** get weston_surface from weston_transmitter_surface
+ *
+ * \param txs The Transmitter surface.
+ */
+ struct weston_surface *
+ (*get_weston_surface)(struct weston_transmitter_surface *txs);
+
+ struct weston_transmitter_remote *
+ (*get_transmitter_remote)(const char *output_name, struct weston_transmitter *transmitter);
+};
+
+static inline const struct weston_transmitter_api *
+weston_get_transmitter_api(struct weston_compositor *compositor)
+{
+ return weston_plugin_api_get(compositor, WESTON_TRANSMITTER_API_NAME,
+ sizeof(struct weston_transmitter_api));
+}
+
+#define WESTON_TRANSMITTER_IVI_API_NAME "transmitter_ivi_v1"
+
+/** For relaying configure events from Transmitter to shell. */
+typedef void (*weston_transmitter_ivi_resize_handler_t)(void *data,
+ int32_t width,
+ int32_t height);
+
+/** The Transmitter IVI-shell API
+ *
+ * Contains the IVI-shell specifics required to remote an ivi-surface.
+ */
+struct weston_transmitter_ivi_api {
+ /** Set IVI-id for a transmitter surface
+ *
+ * \param txs The transmitted surface.
+ * \param ivi_id The IVI-surface id as specified by the
+ * ivi_application.surface_create request.
+ */
+ void
+ (*set_ivi_id)(struct weston_transmitter_surface *txs, uint32_t ivi_id);
+
+ /** Set callback to relay configure events.
+ *
+ * \param txs The transmitted surface.
+ * \param cb The callback function pointer.
+ * \param data User data to be passed to the callback.
+ *
+ * The arguments to the callback function are user data, and width and
+ * height from the configure event from the remote compositor. The
+ * shell must relay this event to the application.
+ */
+ void
+ (*set_resize_callback)(struct weston_transmitter_surface *txs,
+ weston_transmitter_ivi_resize_handler_t cb,
+ void *data);
+};
+
+static inline const struct weston_transmitter_ivi_api *
+weston_get_transmitter_ivi_api(struct weston_compositor *compositor)
+{
+ return weston_plugin_api_get(compositor,
+ WESTON_TRANSMITTER_IVI_API_NAME,
+ sizeof(struct weston_transmitter_ivi_api));
+}
+
+/** Identifies outputs created by the Transmitter by make */
+#define WESTON_TRANSMITTER_OUTPUT_MAKE "Weston-Transmitter"
+
+/* Remote compositor/output are identified by model */
+
+
+struct renderer {
+ void (*repaint_output)(struct weston_transmitter_output *output);
+ struct GstAppContext *ctx;
+ int32_t dmafd; /* dmafd received from compositor-drm */
+ int buf_stride;
+ int surface_width;
+ int surface_height;
+ bool recorder_enabled;
+};
+
+#endif /* WESTON_TRANSMITTER_API_H */
diff --git a/include/waltham-renderer.h b/include/waltham-renderer.h
new file mode 100644
index 0000000..268a002
--- /dev/null
+++ b/include/waltham-renderer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 Advanced Driver Information Technology GmbH, Advanced Driver Information Technology Corporation, Robert Bosch GmbH, Robert Bosch Car Multimedia GmbH, DENSO Corporation
+ *
+ * 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 TRANSMITTER_WALTHAM_RENDERER_H_
+#define TRANSMITTER_WALTHAM_RENDERER_H_
+
+struct weston_transmitter_output;
+
+struct waltham_renderer_interface {
+ int (*display_create)(struct weston_transmitter_output *output);
+};
+
+struct gst_settings {
+ int width;
+ int height;
+ int bitrate;
+ char *ip;
+ int port;
+};
+
+#endif /* TRANSMITTER_WALTHAM_RENDERER_H_ */
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..43c8cf4
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,58 @@
+project('waltham-transmitter',
+ '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-transmitter @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 = ''
+libweston_major_version = '8'
+libweston_version = 'libweston-@0@'.format(libweston_major_version)
+libweston_dep = dependency(libweston_version)
+
+libwayland_dep = dependency('wayland-server')
+libwaltham_dep = dependency('waltham')
+weston_dep = dependency('weston')
+
+prefix_path = get_option('prefix')
+plugin_dir = join_paths(prefix_path, get_option('libdir'))
+plugin_install_dir = join_paths(plugin_dir, libweston_version)
+common_inc = include_directories('include')
+
+dir_include_waltham_transmiter_install = 'waltham-transmitter'
+
+subdir('transmitter-plugin')
+subdir('include')
diff --git a/transmitter-plugin/input.c b/transmitter-plugin/input.c
new file mode 100644
index 0000000..8fb543c
--- /dev/null
+++ b/transmitter-plugin/input.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (C) 2017 Advanced Driver Information Technology Joint Venture 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.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+/* for fake stuff */
+#include <math.h>
+
+#include <wayland-client.h>
+#include <libweston/libweston.h>
+
+#include <weston.h>
+#include "plugin.h"
+#include "transmitter_api.h"
+
+/** @file
+ *
+ * This is an implementation of a remote input.
+ *
+ * Request wl_data_device_manager.get_data_device would need to be blocked,
+ * except maybe it's not necessary, we just "forget" to forward data to/from
+ * the remote wl_seat. It might still work inside the local compositor.
+ *
+ * weston_compositor_set_default_pointer_grab() will break our pointer
+ * implementation, but no in-tree code is calling it.
+ */
+
+/* XXX: all functions and variables with a name, and things marked with a
+ * comment, containing the word "fake" are mockups that need to be
+ * removed from the final implementation.
+ */
+
+static void
+pointer_focus_grab_handler(struct weston_pointer_grab *grab)
+{
+ /* No-op:
+ *
+ * Weston internal events do not change the focus.
+ */
+}
+
+static void
+pointer_motion_grab_handler(struct weston_pointer_grab *grab,
+ const struct timespec *time,
+ struct weston_pointer_motion_event *event)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_button_grab_handler(struct weston_pointer_grab *grab,
+ const struct timespec *time,
+ uint32_t button,
+ uint32_t state)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_axis_grab_handler(struct weston_pointer_grab *grab,
+ const struct timespec *time,
+ struct weston_pointer_axis_event *event)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_axis_source_grab_handler(struct weston_pointer_grab *grab,
+ uint32_t source)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_frame_grab_handler(struct weston_pointer_grab *grab)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_cancel_grab_handler(struct weston_pointer_grab *grab)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+/* These handlers would be called from the notify_*() functions in src/input.c.
+ * However, as we do not use the low level input notify_*() functions that
+ * backends drive, these are mostly uncalled, except the focus handler which
+ * weston core generates internally.
+ */
+static const struct weston_pointer_grab_interface pointer_grab_impl = {
+ pointer_focus_grab_handler,
+ pointer_motion_grab_handler,
+ pointer_button_grab_handler,
+ pointer_axis_grab_handler,
+ pointer_axis_source_grab_handler,
+ pointer_frame_grab_handler,
+ pointer_cancel_grab_handler,
+};
+
+static void
+keyboard_grab_key(struct weston_keyboard_grab *grab,
+ const struct timespec *time,
+ uint32_t key,
+ uint32_t state)
+{
+}
+
+static void
+keyboard_grab_modifiers(struct weston_keyboard_grab *grab,
+ uint32_t serial,
+ uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked,
+ uint32_t group)
+{
+}
+
+static void
+keyboard_grab_cancel(struct weston_keyboard_grab *grab)
+{
+}
+
+static const struct weston_keyboard_grab_interface keyborad_grab_impl = {
+ keyboard_grab_key,
+ keyboard_grab_modifiers,
+ keyboard_grab_cancel
+};
+
+static void
+touch_grab_down_handler(struct weston_touch_grab *grab,
+ const struct timespec *time,
+ int touch_id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+}
+
+static void
+touch_grab_up_handler(struct weston_touch_grab *grab,
+ const struct timespec *time,
+ int touch_id)
+{
+}
+
+static void
+touch_grab_motion_handler(struct weston_touch_grab *grab,
+ const struct timespec *time,
+ int touch_id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+}
+
+static void
+touch_grab_frame_handler(struct weston_touch_grab *grab)
+{
+}
+
+static void
+touch_grab_cancel_handler(struct weston_touch_grab *grab)
+{
+}
+
+static const struct weston_touch_grab_interface touch_grab_impl = {
+ touch_grab_down_handler,
+ touch_grab_up_handler,
+ touch_grab_motion_handler,
+ touch_grab_frame_handler,
+ touch_grab_cancel_handler,
+};
+
+static struct weston_pointer_client *
+weston_pointer_get_pointer_client(struct weston_pointer *pointer,
+ struct wl_client *client)
+{
+ struct weston_pointer_client *pointer_client;
+
+ wl_list_for_each(pointer_client, &pointer->pointer_clients, link) {
+ if (pointer_client->client == client)
+ return pointer_client;
+ }
+
+ return NULL;
+}
+
+/* The different ways to get pointer focus on a remoted surface:
+ *
+ * 1. Transmitter seat has pointer. The client has wl_pointer. Transmitter
+ * receives pointer.enter. (transmitter_seat_pointer_enter())
+ *
+ * 2. Transmitter seat has pointer. Transmitter has received pointer.enter.
+ * The client calls wl_seat.get_pointer. => send enter only on the new
+ * wl_pointer. (seat_get_pointer_handler())
+ *
+ * 3. Client has wl_pointer. Transmitter seat adds pointer capability.
+ * Transmitter receives pointer.enter. wl_pointer MUST NOT enter,
+ * specified by wl_seat.capabilities.
+ *
+ * By definition, Transmitter cannot receive pointer.enter without having
+ * pointer capability in the seat, so no other combinations are possible.
+ *
+ * The same applies to wl_keyboard and wl_touch.
+ */
+
+/* Implementor notes:
+ *
+ * The handling of all of wl_pointer, wl_keyboard and wl_touch should be
+ * similar. To make it work, we need to add a signal to each of the
+ * wl_seat.get_pointer, wl_seat.get_keyboard, and wl_seat.get_touch request
+ * handlers in Weston core. Otherwise we cannot implement the case 2 of gaining
+ * input device focus.
+ *
+ * However, weston_keyboard::focus is a weston_surface, not a weston_view, so
+ * we may be able to leverage more of the core implementation and maybe do
+ * without the wl_seat.get_keyboard signal. Weston_touch uses a weston_view, so
+ * that is similar to weston_pointer.
+ *
+ * It might be useful to convert weston_keyboard and weston_touch to use a
+ * similar thing as weston_pointer_client, in case it makes things more
+ * consistent. It might also fix issues when a client has multiple copies of a
+ * wl_keyboard or a wl_touch, but that is getting off-topic.
+ *
+ * This file shows which part of the Weston input path we skip and where we
+ * hook in. We skip everything starting from the notify_*() API used by
+ * backends, and stub out the grab handlers. Instead of actual grab handlers,
+ * we have our own network protocol events handlers. They do much of the same
+ * as normal grab handlers would do, except focus is pre-given, and we do not
+ * have weston_view for the focus surfaces, so we need to bypass core code
+ * dealing with those.
+ *
+ * Our remote seat implementation will leave many struct members unused and
+ * replicate some from weston_pointer, weston_keyboard, and weston_touch.
+ * Weston core must be kept out from the focus handling business, because we
+ * will send enter/leave events ourselves, and focus assignments are given
+ * to us from the remote, they cannot be changed at will by the local Weston.
+ */
+
+/** Callback from the protocol request handler for wl_seat.get_pointer
+ *
+ * The Weston core handler never sees focus set on the weston_pointer,
+ * so it won't send wl_pointer.enter nor set focus_client. It does call
+ * weston_pointer_ensure_pointer_client() though.
+ */
+void
+seat_get_pointer_handler(struct wl_listener *listener, void *data)
+{
+ struct wl_resource *new_pointer = data;
+ struct weston_transmitter_seat *seat;
+ struct wl_resource *surface;
+ struct weston_pointer_client *pointer_client;
+ struct wl_client *client;
+ struct weston_pointer *pointer;
+
+ seat = wl_container_of(listener, seat, get_pointer_listener);
+ if (!seat->pointer_focus)
+ return;
+
+ client = wl_resource_get_client(new_pointer);
+ surface = seat->pointer_focus->surface->resource;
+
+ if (wl_resource_get_client(surface) != client)
+ return;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer); /* guaranteed by having pointer_focus */
+ pointer_client = weston_pointer_get_pointer_client(pointer, client);
+
+ if (!pointer->focus_client)
+ pointer->focus_client = pointer_client;
+ else
+ assert(pointer->focus_client == pointer_client);
+
+ wl_pointer_send_enter(new_pointer, pointer->focus_serial, surface,
+ seat->pointer_surface_x, seat->pointer_surface_y);
+
+ if (wl_resource_get_version(new_pointer) >=
+ WL_POINTER_FRAME_SINCE_VERSION)
+ wl_pointer_send_frame(new_pointer);
+}
+
+static void
+transmitter_seat_create_pointer(struct weston_transmitter_seat *seat)
+{
+ struct weston_pointer *pointer;
+
+ seat->pointer_phase = 0.0;
+ seat->pointer_surface_x = wl_fixed_from_int(-1000000);
+ seat->pointer_surface_y = wl_fixed_from_int(-1000000);
+ seat->pointer_focus = NULL;
+ wl_list_init(&seat->pointer_focus_destroy_listener.link);
+
+ weston_seat_init_pointer(seat->base);
+
+ pointer = weston_seat_get_pointer(seat->base);
+
+ /* not exported:
+ * weston_pointer_set_default_grab(pointer, &pointer_grab_impl); */
+ pointer->default_grab.interface = &pointer_grab_impl;
+
+ /* Changes to local outputs are irrelevant. */
+ wl_list_remove(&pointer->output_destroy_listener.link);
+ wl_list_init(&pointer->output_destroy_listener.link);
+
+ weston_log("Transmitter created pointer=%p for seat %p\n",
+ pointer, seat->base);
+}
+
+static void
+seat_pointer_focus_destroy_handler(struct wl_listener *listener, void *data)
+{
+ struct weston_transmitter_surface *txs = data;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(listener, seat, pointer_focus_destroy_listener);
+ assert(seat->pointer_focus == txs);
+
+ seat->pointer_focus = NULL;
+}
+
+void
+transmitter_seat_pointer_enter(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+
+ assert(txs->surface);
+ //struct wl_client *client = wl_resource_get_client(txs->surface->resource);
+
+ seat->pointer_focus = txs;
+ seat->pointer_focus_destroy_listener.notify =
+ seat_pointer_focus_destroy_handler;
+ wl_signal_add(&txs->destroy_signal,
+ &seat->pointer_focus_destroy_listener);
+
+ /* If pointer-focus gets destroyed, txs will get destroyed, the
+ * remote surface object is destroyed, and the remote will send a
+ * leave and a frame.
+ */
+
+ seat->pointer_surface_x = surface_x;
+ seat->pointer_surface_y = surface_y;
+
+ pointer->focus_serial = serial;
+
+ /* pointer->focus is not used, because it is a weston_view, while
+ * remoted surfaces have no views.
+ *
+ * pointer->x,y are not used because they are in global coordinates.
+ * Remoted surfaces are not in the global space at all, so there are
+ * no such coordinates.
+ */
+
+ if (!pointer->focus_client)
+ return;
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list) {
+ wl_pointer_send_enter(resource,
+ serial,
+ txs->surface->resource,
+ surface_x, surface_y);
+ }
+}
+
+void
+transmitter_seat_pointer_leave(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *surface_resource;
+ struct wl_resource *resource;
+
+ if (txs != seat->pointer_focus) {
+ weston_log("Transmitter Warning: pointer leave for %p, expected %p\n",
+ txs, seat->pointer_focus);
+ }
+
+ seat->pointer_focus = NULL;
+ wl_list_remove(&seat->pointer_focus_destroy_listener.link);
+ wl_list_init(&seat->pointer_focus_destroy_listener.link);
+
+ if (!txs)
+ return;
+ assert(txs->surface);
+ surface_resource = txs->surface->resource;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+ if (!pointer->focus_client)
+ return;
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list)
+ wl_pointer_send_leave(resource, serial, surface_resource);
+
+ /* Do not reset pointer->focus_client, because we need to be able
+ * to send a following 'frame' event in
+ * transmitter_seat_pointer_frame().
+ */
+}
+
+void
+transmitter_seat_pointer_motion(struct weston_transmitter_seat *seat,
+ uint32_t time,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+ struct weston_transmitter_surface *txs;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+
+ seat->pointer_surface_x = surface_x;
+ seat->pointer_surface_y = surface_y;
+
+ if (!pointer->focus_client)
+ return;
+
+ txs = seat->pointer_focus;
+ if (txs)
+ assert(wl_resource_get_client(txs->surface->resource) ==
+ pointer->focus_client->client);
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list) {
+ wl_pointer_send_motion(resource, time,
+ surface_x, surface_y);
+ }
+}
+
+void
+transmitter_seat_pointer_button(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t button,
+ uint32_t state)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+ struct weston_transmitter_surface *txs;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+
+ if (!pointer->focus_client)
+ return;
+
+ txs = seat->pointer_focus;
+ if (txs)
+ assert(wl_resource_get_client(txs->surface->resource) ==
+ pointer->focus_client->client);
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list) {
+ wl_pointer_send_button(resource, serial, time,
+ button, state);
+ }
+}
+
+void
+transmitter_seat_pointer_axis(struct weston_transmitter_seat *seat,
+ uint32_t time,
+ uint32_t axis,
+ wl_fixed_t value)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+ struct weston_transmitter_surface *txs;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+
+ if (!pointer->focus_client)
+ return;
+
+ txs = seat->pointer_focus;
+ if (txs)
+ assert(wl_resource_get_client(txs->surface->resource) ==
+ pointer->focus_client->client);
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list) {
+ wl_pointer_send_axis(resource, time,
+ axis, value);
+ }
+}
+
+void
+transmitter_seat_pointer_frame(struct weston_transmitter_seat *seat)
+{
+ struct weston_pointer *pointer;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ if (pointer)
+ weston_pointer_send_frame(pointer);
+}
+
+void
+transmitter_seat_pointer_axis_source(struct weston_transmitter_seat *seat,
+ uint32_t axis_source)
+{
+ /* ToDo : implement axis event handling */
+}
+
+void
+transmitter_seat_pointer_axis_stop(struct weston_transmitter_seat *seat,
+ uint32_t time,
+ uint32_t axis)
+{
+ /* ToDo : implement axis event handling */
+}
+
+void
+transmitter_seat_pointer_axis_discrete(struct weston_transmitter_seat *seat,
+ uint32_t axis,
+ int32_t discrete)
+{
+ /* ToDo : implement axis event handling */
+}
+
+static void
+transmitter_seat_create_keyboard(struct weston_transmitter_seat *seat)
+{
+ struct weston_keyboard *keyboard;
+
+ seat->keyboard_focus = NULL;
+ weston_seat_init_keyboard(seat->base, NULL);
+
+ keyboard = weston_seat_get_keyboard(seat->base);
+
+ keyboard->default_grab.interface = &keyborad_grab_impl;
+
+ weston_log("Transmitter created keyboard=%p for seat %p\n",
+ keyboard, seat->base);
+}
+
+static void
+transmitter_seat_keyboard_enter(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs,
+ struct wl_array *keys)
+{
+ struct weston_keyboard *keyboard;
+ struct wl_resource *resource = NULL;
+ struct wl_resource *surface_resource;
+
+ keyboard = weston_seat_get_keyboard(seat->base);
+ assert(keyboard);
+
+ assert(txs->surface);
+ surface_resource = txs->surface->resource;
+
+ seat->keyboard_focus = txs;
+ wl_array_copy(&keyboard->keys, keys);
+
+ wl_resource_for_each(resource, &keyboard->resource_list) {
+ if (wl_resource_get_client(resource) == wl_resource_get_client(surface_resource)) {
+ wl_keyboard_send_enter(resource,
+ serial,
+ surface_resource,
+ &keyboard->keys);
+ }
+ }
+}
+
+static void
+transmitter_seat_keyboard_leave(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs)
+{
+ struct weston_keyboard *keyboard;
+ struct wl_resource *resource = NULL;
+ struct wl_resource *surface_resource;
+
+ keyboard = weston_seat_get_keyboard(seat->base);
+ assert(keyboard);
+
+ assert(txs->surface);
+ surface_resource = txs->surface->resource;
+
+ wl_resource_for_each(resource, &keyboard->resource_list) {
+ if (wl_resource_get_client(resource) == wl_resource_get_client(surface_resource)) {
+ wl_keyboard_send_leave(resource,
+ serial,
+ surface_resource);
+ }
+ }
+}
+
+static void
+transmitter_seat_keyboard_key(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t key,
+ uint32_t state)
+{
+ struct weston_keyboard *keyboard;
+ struct wl_resource *resource = NULL;
+
+ keyboard = weston_seat_get_keyboard(seat->base);
+ assert(keyboard);
+
+ wl_resource_for_each(resource, &keyboard->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->keyboard_focus->surface->resource)) {
+ wl_keyboard_send_key(resource,
+ serial,
+ time,
+ key,
+ state);
+ }
+ }
+}
+
+static void
+transmitter_seat_create_touch(struct weston_transmitter_seat *seat)
+{
+ struct weston_touch *touch;
+
+ seat->touch_focus = NULL;
+ weston_seat_init_touch(seat->base);
+
+ touch = weston_seat_get_touch(seat->base);
+
+ touch->default_grab.interface = &touch_grab_impl;
+
+ weston_log("Transmitter created touch=%p for seat %p\n",
+ touch, seat->base);
+}
+
+static void
+transmitter_seat_touch_down (struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ uint32_t time,
+ struct weston_transmitter_surface *txs,
+ int32_t touch_id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+ struct wl_resource *surface_resource;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ assert(txs->surface);
+ surface_resource = txs->surface->resource;
+
+ seat->touch_focus = txs;
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) == wl_resource_get_client(surface_resource)) {
+ wl_touch_send_down(resource, serial, time,
+ surface_resource,
+ touch_id, x, y);
+ }
+ }
+}
+
+static void
+transmitter_seat_touch_up (struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ uint32_t time,
+ int32_t touch_id)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->touch_focus->surface->resource)) {
+ wl_touch_send_up(resource, serial, time, touch_id);
+ }
+ }
+}
+
+static void
+transmitter_seat_touch_motion (struct weston_transmitter_seat *seat,
+ uint32_t time,
+ int32_t touch_id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->touch_focus->surface->resource)) {
+ wl_touch_send_motion(resource, time, touch_id, x, y);
+ }
+ }
+}
+
+static void
+transmitter_seat_touch_frame (struct weston_transmitter_seat *seat)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->touch_focus->surface->resource)) {
+ wl_touch_send_frame(resource);
+ }
+ }
+}
+
+static void
+transmitter_seat_touch_cancel (struct weston_transmitter_seat *seat)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->touch_focus->surface->resource)) {
+ wl_touch_send_cancel(resource);
+ }
+ }
+}
+
+static char *
+make_seat_name(struct weston_transmitter_remote *remote, const char *name)
+{
+ char *str;
+
+ if (asprintf(&str, "transmitter-%s-%s", remote->addr, name) < 0)
+ return NULL;
+
+ return str;
+}
+
+void
+transmitter_seat_destroy(struct weston_transmitter_seat *seat)
+{
+ wl_list_remove(&seat->link);
+
+ weston_log("Transmitter destroy seat=%p\n", seat->base);
+
+ wl_list_remove(&seat->get_pointer_listener.link);
+ wl_list_remove(&seat->pointer_focus_destroy_listener.link);
+
+ if (seat->pointer_timer)
+ wl_event_source_remove(seat->pointer_timer);
+
+ free(seat);
+}
+
+static void
+pointer_handle_enter(struct wthp_pointer *wthp_pointer,
+ uint32_t serial,
+ struct wthp_surface *surface,
+ wth_fixed_t surface_x,
+ wth_fixed_t surface_y)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ if (txs != seat->pointer_focus)
+ transmitter_seat_pointer_leave(seat, serial, seat->pointer_focus);
+ transmitter_seat_pointer_enter(seat, serial, txs,
+ surface_x, surface_y);
+ }
+ }
+}
+
+static void
+pointer_handle_leave(struct wthp_pointer *wthp_pointer,
+ uint32_t serial,
+ struct wthp_surface *surface)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ transmitter_seat_pointer_leave(seat, serial, txs);
+ }
+ }
+}
+
+static void
+pointer_handle_motion(struct wthp_pointer *wthp_pointer,
+ uint32_t time,
+ wth_fixed_t surface_x,
+ wth_fixed_t surface_y)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_pointer_motion(seat, time,
+ surface_x,
+ surface_y);
+}
+
+static void
+pointer_handle_button(struct wthp_pointer *wthp_pointer,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t button,
+ uint32_t state)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_pointer_button(seat, serial,
+ time, button,
+ state);
+}
+
+static void
+pointer_handle_axis(struct wthp_pointer *wthp_pointer,
+ uint32_t time,
+ uint32_t axis, wth_fixed_t value)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_pointer_axis(seat, time,
+ axis, value);
+}
+
+static void
+pointer_handle_frame(struct wthp_pointer *wthp_pointer)
+{
+ /* ToDo : implement pointer handle frame */
+}
+
+static void
+pointer_handle_axis_source(struct wthp_pointer *wthp_pointer,
+ uint32_t axis_source)
+{
+ /* ToDo : implement pointer handle axis source */
+}
+
+static void
+pointer_handle_axis_stop(struct wthp_pointer *wthp_pointer,
+ uint32_t time,
+ uint32_t axis)
+{
+ /* ToDo : implement pointer handle axis stop */
+}
+
+static void
+pointer_handle_axis_discrete(struct wthp_pointer *wthp_pointer,
+ uint32_t axis,
+ int32_t discrete)
+{
+ /* ToDo : implement pointer handle axis discrete */
+}
+
+static const struct wthp_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
+};
+
+static void
+keyboard_handle_keymap(struct wthp_keyboard * wthp_keyboard,
+ uint32_t format,
+ uint32_t keymap_sz,
+ void * keymap)
+{
+ /* ToDo : implement keyboard handle keymap */
+}
+
+static void
+keyboard_handle_enter(struct wthp_keyboard *wthp_keyboard,
+ uint32_t serial,
+ struct wthp_surface *surface,
+ struct wth_array *keys)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_keyboard);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+ struct wl_array *wl_key = (struct wl_array *)malloc(sizeof(struct wl_array));
+
+ wl_key->size = keys->size;
+ wl_key->alloc = keys->alloc;
+ wl_key->data = keys->data;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ //transmitter_seat_keyboard_enter(seat, serial, txs, keys);
+ transmitter_seat_keyboard_enter(seat, serial, txs, wl_key);
+ }
+ }
+ free(wl_key);
+}
+
+static void
+keyboard_handle_leave(struct wthp_keyboard *wthp_keyboard,
+ uint32_t serial,
+ struct wthp_surface *surface)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_keyboard);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ transmitter_seat_keyboard_leave(seat, serial, txs);
+ }
+ }
+}
+
+static void
+keyboard_handle_key(struct wthp_keyboard *wthp_keyboard,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t key,
+ uint32_t state)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_keyboard);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_keyboard_key(seat, serial, time, key, state);
+}
+
+static void
+keyboard_handle_modifiers(struct wthp_keyboard *wthp_keyboard,
+ uint32_t serial,
+ uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked,
+ uint32_t group)
+{
+ weston_log("keyboard_handle_modifiers\n");
+}
+
+static void
+keyboard_handle_repeat_info(struct wthp_keyboard *wthp_keyboard,
+ int32_t rate,
+ int32_t delay)
+{
+ weston_log("keyboard_handle_repeat_info\n");
+}
+
+static const struct wthp_keyboard_listener keyboard_listener = {
+ keyboard_handle_keymap,
+ keyboard_handle_enter,
+ keyboard_handle_leave,
+ keyboard_handle_key,
+ keyboard_handle_modifiers,
+ keyboard_handle_repeat_info
+};
+
+static void
+touch_handle_down (struct wthp_touch * wthp_touch,
+ uint32_t serial,
+ uint32_t time,
+ struct wthp_surface * surface,
+ int32_t id,
+ wth_fixed_t x,
+ wth_fixed_t y)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ transmitter_seat_touch_down(seat, serial, time,
+ txs, id, x, y);
+ }
+ }
+}
+
+static void
+touch_handle_up (struct wthp_touch * wthp_touch,
+ uint32_t serial,
+ uint32_t time,
+ int32_t id)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_touch_up(seat, serial, time, id);
+}
+
+static void
+touch_handle_motion (struct wthp_touch * wthp_touch,
+ uint32_t time,
+ int32_t id,
+ wth_fixed_t x,
+ wth_fixed_t y)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_touch_motion(seat, time, id, x, y);
+}
+
+
+static void
+touch_handle_frame (struct wthp_touch * wthp_touch)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_touch_frame(seat);
+}
+
+static void
+touch_handle_cancel (struct wthp_touch * wthp_touch)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_touch_cancel(seat);
+}
+
+
+static const struct wthp_touch_listener touch_listener = {
+ touch_handle_down,
+ touch_handle_up,
+ touch_handle_motion,
+ touch_handle_frame,
+ touch_handle_cancel
+};
+
+void
+seat_capabilities(struct wthp_seat *wthp_seat,
+ enum wthp_seat_capability caps)
+{
+ struct waltham_display *dpy = wth_object_get_user_data((struct wth_object *)wthp_seat);
+
+ weston_log("seat_capabilities\n");
+
+ if ((caps & WTHP_SEAT_CAPABILITY_POINTER) && !dpy->pointer)
+ {
+ weston_log("WTHP_SEAT_CAPABILITY_POINTER\n");
+ dpy->pointer = wthp_seat_get_pointer(dpy->seat);
+ wthp_pointer_set_listener(dpy->pointer, &pointer_listener, dpy);
+ }
+ if ((caps & WTHP_SEAT_CAPABILITY_KEYBOARD) && !dpy->keyboard)
+ {
+ weston_log("WTHP_SEAT_CAPABILITY_KEYBOARD\n");
+ dpy->keyboard = wthp_seat_get_keyboard(dpy->seat);
+ wthp_keyboard_set_listener(dpy->keyboard, &keyboard_listener, dpy);
+ }
+ if ((caps & WTHP_SEAT_CAPABILITY_TOUCH) && !dpy->touch)
+ {
+ weston_log("WTHP_SEAT_CAPABILITY_TOUCH\n");
+ dpy->touch = wthp_seat_get_touch(dpy->seat);
+ wthp_touch_set_listener(dpy->touch, &touch_listener, dpy);
+ }
+}
+
+int
+transmitter_remote_create_seat(struct weston_transmitter_remote *remote)
+{
+ struct weston_transmitter_seat *seat = NULL;
+ char *name = NULL;
+ struct weston_seat *weston_seat = NULL;
+
+ seat = zalloc(sizeof *seat);
+ if (!seat)
+ goto fail;
+
+ wl_list_init(&seat->get_pointer_listener.link);
+ wl_list_init(&seat->pointer_focus_destroy_listener.link);
+
+ /* XXX: get the name from remote */
+ name = make_seat_name(remote, "default");
+ if (!name)
+ goto fail;
+
+
+ if (wl_list_empty(&remote->transmitter->compositor->seat_list)) {
+ weston_seat = zalloc(sizeof *weston_seat);
+ if (!weston_seat)
+ goto fail;
+
+ weston_seat_init(weston_seat, remote->transmitter->compositor, name);
+ seat->base = weston_seat;
+ weston_log("Transmitter created seat=%p \n", &seat->base);
+ } else {
+ wl_list_for_each(weston_seat, &remote->transmitter->compositor->seat_list, link) {
+ weston_log("Transmitter weston_seat %p\n", weston_seat);
+ seat->base = weston_seat;
+ }
+ }
+
+ free(name);
+#if DEBUG
+ weston_seat_init(&seat->base, remote->transmitter->compositor, name);
+ free(name);
+
+ /* Hide the weston_seat from the rest of Weston, there are too many
+ * things making assumptions:
+ * - backends assume they control all seats
+ * - shells assume they control all input foci
+ * We do not want either to mess with our seat.
+ */
+ wl_list_remove(&seat->base.link);
+ wl_list_init(&seat->base.link);
+
+ /* The weston_compositor::seat_created_signal has already been
+ * emitted. Shells use it to subscribe to focus changes, but we should
+ * never handle focus with weston core... except maybe with keyboard.
+ * text-backend.c will also act on the new seat.
+ * It is possible weston_seat_init() needs to be split to fix this
+ * properly.
+ */
+
+ weston_log("Transmitter created seat=%p '%s'\n",
+ &seat->base, seat->base.seat_name);
+#endif
+
+ /* XXX: mirror remote capabilities */
+ transmitter_seat_create_pointer(seat);
+ transmitter_seat_create_keyboard(seat);
+ transmitter_seat_create_touch(seat);
+
+ wl_list_insert(&remote->seat_list, &seat->link);
+
+ return 0;
+
+fail:
+ free(seat);
+ free(name);
+
+ return -1;
+}
+
+static void
+fake_pointer_get_position(struct weston_transmitter_seat *seat, double step,
+ wl_fixed_t *x, wl_fixed_t *y)
+{
+ double s, c;
+
+ seat->pointer_phase += step;
+ while (seat->pointer_phase > 2.0 * M_PI)
+ seat->pointer_phase -= 2.0 * M_PI;
+
+ sincos(seat->pointer_phase, &s, &c);
+ *x = wl_fixed_from_double(100.0 + 50.0 * c);
+ *y = wl_fixed_from_double(100.0 + 50.0 * s);
+}
+
+static int
+fake_pointer_timer_handler(void *data)
+{
+ struct weston_transmitter_seat *seat = data;
+ wl_fixed_t x, y;
+ uint32_t time;
+ struct timespec timespec;
+
+ weston_compositor_get_time(&timespec);
+ time=timespec.tv_sec * 1000 + timespec.tv_nsec / 1000000;
+
+ fake_pointer_get_position(seat, 18.0 / 180.0 * M_PI, &x, &y);
+ transmitter_seat_pointer_motion(seat, time, x, y);
+ transmitter_seat_pointer_frame(seat);
+
+ wl_event_source_timer_update(seat->pointer_timer, 100);
+
+ return 0;
+}
+
+int
+transmitter_seat_fake_pointer_input(struct weston_transmitter_seat *seat,
+ struct weston_transmitter_surface *txs)
+{
+ struct wl_event_loop *loop;
+ wl_fixed_t x, y;
+ uint32_t serial = 5;
+
+ /* remove focus from earlier surface */
+ transmitter_seat_pointer_leave(seat, serial++, seat->pointer_focus);
+ transmitter_seat_pointer_frame(seat);
+
+ /* set pointer focus to surface */
+ fake_pointer_get_position(seat, 0.0, &x, &y);
+ transmitter_seat_pointer_enter(seat, serial++, txs, x, y);
+ transmitter_seat_pointer_frame(seat);
+
+ if (!seat->pointer_timer) {
+ /* schedule timer for motion */
+ loop = wl_display_get_event_loop(seat->base->compositor->wl_display);
+ seat->pointer_timer = wl_event_loop_add_timer(loop,
+ fake_pointer_timer_handler, seat);
+ wl_event_source_timer_update(seat->pointer_timer, 100);
+ }
+
+ /* XXX: if the now focused surface disappears, we should call
+ * transmitter_seat_pointer_leave() as part of the mockup. Otherwise
+ * you get a "Transmitter Warning: no pointer->focus_client?".
+ */
+
+ return 0;
+}
diff --git a/transmitter-plugin/meson.build b/transmitter-plugin/meson.build
new file mode 100644
index 0000000..7efd1ce
--- /dev/null
+++ b/transmitter-plugin/meson.build
@@ -0,0 +1,24 @@
+
+libpixman_dep = dependency('pixman-1')
+
+deps_transmiter_plugin = [
+ libwayland_dep,
+ libpixman_dep,
+ libweston_dep,
+ libwaltham_dep,
+ weston_dep,
+ cc.find_library('m')
+]
+
+plugin_transmitter = shared_library(
+ 'waltham-transmitter',
+ 'input.c',
+ 'output.c',
+ 'plugin.c',
+ include_directories: common_inc,
+ dependencies: deps_transmiter_plugin,
+ name_prefix: '',
+ install: true,
+ install_dir: plugin_install_dir,
+)
+env_modmap += 'transmitter-plugin.so=@0@;'.format(plugin_transmitter.full_path())
diff --git a/transmitter-plugin/output.c b/transmitter-plugin/output.c
new file mode 100644
index 0000000..8aff75d
--- /dev/null
+++ b/transmitter-plugin/output.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 Advanced Driver Information Technology Joint Venture 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 <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <libweston/libweston.h>
+
+#include "plugin.h"
+#include "transmitter_api.h"
+
+void
+transmitter_output_destroy(struct weston_transmitter_output *output)
+{
+ wl_list_remove(&output->link);
+ free(output);
+}
+
+int
+transmitter_remote_create_output_with_name(struct weston_transmitter_remote *remote, char *name)
+{
+ struct weston_transmitter_output *output;
+
+ output = zalloc(sizeof(*output));
+ if (!output)
+ return -1;
+
+ output->remote = remote;
+ output->name = name;
+ wl_list_insert(&remote->output_list, &output->link);
+
+ return 0;
+}
diff --git a/transmitter-plugin/plugin.c b/transmitter-plugin/plugin.c
new file mode 100644
index 0000000..2fb60b6
--- /dev/null
+++ b/transmitter-plugin/plugin.c
@@ -0,0 +1,1024 @@
+/*
+ * Copyright (C) 2017 Advanced Driver Information Technology Joint Venture 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 <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <linux/input.h>
+
+#include <libweston/libweston.h>
+#include <libweston/plugin-registry.h>
+
+#include <weston.h>
+#include <ivi-layout-export.h>
+
+#include "plugin.h"
+#include "transmitter_api.h"
+
+/* waltham */
+#include <errno.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <waltham-object.h>
+#include <waltham-client.h>
+#include <waltham-connection.h>
+
+#define MAX_EPOLL_WATCHES 2
+#define ESTABLISH_CONNECTION_PERIOD 2000
+#define RETRY_CONNECTION_PERIOD 5000
+
+static const struct wthp_seat_listener seat_listener = {
+ seat_capabilities,
+ NULL
+};
+
+/* XXX: all functions and variables with a name, and things marked with a
+ * comment, containing the word "fake" are mockups that need to be
+ * removed from the final implementation.
+ */
+
+/** Send configure event through ivi-shell.
+ *
+ * \param txs The Transmitter surface.
+ * \param width Suggestion for surface width.
+ * \param height Suggestion for surface height.
+ *
+ * When the networking code receives a ivi_surface.configure event, it calls
+ * this function to relay it to the application.
+ *
+ * \c txs cannot be a zombie, because transmitter_surface_zombify() must
+ * tear down the network link, so a zombie cannot receive events.
+ */
+void
+transmitter_surface_ivi_resize(struct weston_transmitter_surface *txs,
+ int32_t width, int32_t height)
+{
+ assert(txs->resize_handler);
+ if (!txs->resize_handler)
+ return;
+
+ assert(txs->surface);
+ if (!txs->surface)
+ return;
+
+ txs->resize_handler(txs->resize_handler_data, width, height);
+}
+
+static void
+transmitter_surface_configure(struct weston_transmitter_surface *txs,
+ int32_t dx, int32_t dy)
+{
+ assert(txs->surface);
+ if (!txs->surface)
+ return;
+
+ txs->attach_dx += dx;
+ txs->attach_dy += dy;
+}
+
+static void
+buffer_send_complete(struct wthp_buffer *b, uint32_t serial)
+{
+ if (b)
+ wthp_buffer_destroy(b);
+}
+
+static const struct wthp_buffer_listener buffer_listener = {
+ buffer_send_complete
+};
+
+/*
+ * FIXME: note, at this point, no one is using this.
+ */
+static void
+transmitter_surface_gather_state(struct weston_transmitter_surface *txs)
+{
+ struct weston_transmitter_remote *remote = txs->remote;
+ struct waltham_display *dpy = remote->display;
+
+ if (!dpy->running) {
+ weston_log("transmitter_surface_gather_state() -- dpy not running\n");
+ if (remote->status != WESTON_TRANSMITTER_CONNECTION_DISCONNECTED) {
+ weston_log("transmitter_surface_gather_state() -- disconnected\n");
+
+ remote->status =
+ WESTON_TRANSMITTER_CONNECTION_DISCONNECTED;
+
+ wth_connection_destroy(remote->display->connection);
+ wl_event_source_remove(remote->source);
+ wl_event_source_timer_update(remote->retry_timer, 1);
+ }
+ } else {
+ /* TODO: transmit surface state to remote */
+ /* The buffer must be transmitted to remote side */
+
+ /* waltham */
+ struct weston_surface *surf = txs->surface;
+ struct weston_compositor *comp = surf->compositor;
+ int32_t stride, data_sz, width, height;
+ void *data;
+
+ width = 1;
+ height = 1;
+ stride = width * (PIXMAN_FORMAT_BPP(comp->read_format) / 8);
+
+ data = zalloc(stride * height);
+ data_sz = stride * height;
+
+ /* fake sending buffer */
+ txs->wthp_buf = wthp_blob_factory_create_buffer(remote->display->blob_factory,
+ data_sz, data, surf->width,
+ surf->height, stride,
+ PIXMAN_FORMAT_BPP(comp->read_format));
+
+ wthp_buffer_set_listener(txs->wthp_buf, &buffer_listener, txs);
+
+ wthp_surface_attach(txs->wthp_surf, txs->wthp_buf,
+ txs->attach_dx, txs->attach_dy);
+ wthp_surface_damage(txs->wthp_surf, txs->attach_dx,
+ txs->attach_dy, surf->width, surf->height);
+ wthp_surface_commit(txs->wthp_surf);
+
+ wth_connection_flush(remote->display->connection);
+ free(data);
+ data = NULL;
+ txs->attach_dx = 0;
+ txs->attach_dy = 0;
+ }
+}
+
+/** Mark the weston_transmitter_surface dead.
+ *
+ * Stop all remoting actions on this surface.
+ *
+ * Still keeps the pointer stored by a shell valid, so it can be freed later.
+ */
+static void
+transmitter_surface_zombify(struct weston_transmitter_surface *txs)
+{
+ struct weston_transmitter_remote *remote;
+ /* may be called multiple times */
+ if (!txs->surface)
+ return;
+
+ wl_signal_emit(&txs->destroy_signal, txs);
+
+ wl_list_remove(&txs->surface_destroy_listener.link);
+ txs->surface = NULL;
+
+ wl_list_remove(&txs->sync_output_destroy_listener.link);
+
+ remote = txs->remote;
+
+ if (!remote->display->compositor)
+ weston_log("remote->compositor is NULL\n");
+
+ if (txs->wthp_surf)
+ wthp_surface_destroy(txs->wthp_surf);
+
+ if (txs->wthp_ivi_surface)
+ wthp_ivi_surface_destroy(txs->wthp_ivi_surface);
+
+ /* In case called from destroy_transmitter() */
+ txs->remote = NULL;
+}
+
+static void
+transmitter_surface_destroy(struct weston_transmitter_surface *txs)
+{
+ transmitter_surface_zombify(txs);
+
+ wl_list_remove(&txs->link);
+ free(txs);
+}
+
+/** weston_surface destroy signal handler */
+static void
+transmitter_surface_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_transmitter_surface *txs =
+ wl_container_of(listener, txs, surface_destroy_listener);
+
+ assert(data == txs->surface);
+
+ transmitter_surface_zombify(txs);
+}
+
+void
+sync_output_destroy_handler(struct wl_listener *listener, void *data)
+{
+ struct weston_transmitter_surface *txs;
+
+ txs = wl_container_of(listener, txs, sync_output_destroy_listener);
+
+ wl_list_remove(&txs->sync_output_destroy_listener.link);
+ wl_list_init(&txs->sync_output_destroy_listener.link);
+
+ //weston_surface_force_output(txs->surface, NULL);
+ weston_surface_unmap(txs->surface);
+}
+
+static void
+transmitter_surface_set_ivi_id(struct weston_transmitter_surface *txs,
+ const char *app_id)
+{
+ struct weston_transmitter_remote *remote = txs->remote;
+ struct waltham_display *dpy = remote->display;
+
+ assert(txs->surface);
+
+ if (!dpy)
+ return;
+
+ if (!dpy->compositor)
+ return;
+
+
+ if (!dpy->seat)
+ return;
+
+ if (!dpy->application_id)
+ return;
+
+ txs->wthp_ivi_surface =
+ wthp_ivi_app_id_surface_create(dpy->application_id, app_id, txs->wthp_surf);
+
+ wth_connection_flush(remote->display->connection);
+ if (!txs->wthp_ivi_surface) {
+ weston_log("Failed to create txs->ivi_surf\n");
+ return;
+ }
+
+ weston_log("Created wthp_ivi_surface %p\n", txs->wthp_ivi_surface);
+}
+
+static struct weston_transmitter_surface *
+transmitter_surface_push_to_remote(struct weston_surface *ws, const char *app_id,
+ struct weston_transmitter_remote *remote,
+ struct wl_listener *stream_status)
+{
+ struct weston_transmitter *txr = remote->transmitter;
+ struct weston_transmitter_surface *txs;
+ bool found = false;
+
+ if (remote->status != WESTON_TRANSMITTER_CONNECTION_READY) {
+ return NULL;
+ }
+
+ wl_list_for_each(txs, &remote->surface_list, link) {
+ if (txs->surface == ws) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ txs = NULL;
+ txs = zalloc(sizeof(*txs));
+
+ if (!txs) {
+ weston_log("No memory to create weston_transmitter_surface\n");
+ return NULL;
+ }
+
+ txs->remote = remote;
+ wl_signal_init(&txs->destroy_signal);
+ wl_list_insert(&remote->surface_list, &txs->link);
+
+ txs->status = WESTON_TRANSMITTER_STREAM_INITIALIZING;
+ wl_signal_init(&txs->stream_status_signal);
+ if (stream_status)
+ wl_signal_add(&txs->stream_status_signal, stream_status);
+
+ txs->surface = ws;
+ txs->surface_destroy_listener.notify = transmitter_surface_destroyed;
+ wl_signal_add(&ws->destroy_signal, &txs->surface_destroy_listener);
+
+ wl_list_init(&txs->sync_output_destroy_listener.link);
+
+ wl_list_init(&txs->frame_callback_list);
+ wl_list_init(&txs->feedback_list);
+
+ txs->lyt = weston_plugin_api_get(txr->compositor,
+ IVI_LAYOUT_API_NAME, sizeof(txs->lyt));
+ }
+
+ /* TODO: create the content stream connection... */
+ if (!remote->display->compositor)
+ weston_log("remote->compositor is NULL\n");
+
+ if (!txs->wthp_surf) {
+ txs->wthp_surf = wthp_compositor_create_surface(remote->display->compositor);
+ wth_connection_flush(remote->display->connection);
+
+ transmitter_surface_set_ivi_id(txs, app_id);
+ }
+
+ return txs;
+}
+
+static enum weston_transmitter_stream_status
+transmitter_surface_get_stream_status(struct weston_transmitter_surface *txs)
+{
+ return txs->status;
+}
+
+/* waltham */
+
+/* The server advertises a global interface. We can store the ad for later
+ * and/or bind to it immediately if we want to. We also need to keep track of
+ * the globals we bind to, so that global_remove can be handled properly (not
+ * implemented).
+ */
+static void
+registry_handle_global(struct wthp_registry *registry,
+ uint32_t name,
+ const char *interface,
+ uint32_t version)
+{
+ struct waltham_display *dpy = wth_object_get_user_data((struct wth_object *)registry);
+
+ if (strcmp(interface, "wthp_compositor") == 0) {
+ assert(!dpy->compositor);
+ dpy->compositor = (struct wthp_compositor *)
+ wthp_registry_bind(registry, name, interface, 1);
+ /* has no events to handle */
+ } else if (strcmp(interface, "wthp_blob_factory") == 0) {
+ assert(!dpy->blob_factory);
+ dpy->blob_factory = (struct wthp_blob_factory *)
+ wthp_registry_bind(registry, name, interface, 1);
+ /* has no events to handle */
+ } else if (strcmp(interface, "wthp_seat") == 0) {
+ assert(!dpy->seat);
+ dpy->seat = (struct wthp_seat *)
+ wthp_registry_bind(registry, name, interface, 1);
+ wthp_seat_set_listener(dpy->seat, &seat_listener, dpy);
+ } else if (strcmp(interface, "wthp_ivi_application") == 0) {
+ assert(!dpy->application);
+ dpy->application = (struct wthp_ivi_application *)
+ wthp_registry_bind(registry, name, interface, 1);
+ } else if (strcmp(interface, "wthp_ivi_app_id") == 0) {
+ assert(!dpy->application_id);
+ dpy->application_id = (struct wthp_ivi_app_id *)
+ wthp_registry_bind(registry, name, interface, 1);
+ }
+}
+
+/* notify connection ready */
+static void
+conn_ready_notify(struct wl_listener *l, void *data)
+{
+ struct weston_transmitter_remote *remote =
+ wl_container_of(l, remote, establish_listener);
+
+ weston_log("conn_ready_notify()\n");
+
+ /* Outputs and seats are dynamic, do not guarantee they are all
+ * present when signalling connection status.
+ */
+ transmitter_remote_create_output_with_name(remote, strdup(remote->model));
+ transmitter_remote_create_seat(remote);
+}
+
+/* waltham */
+/* The server removed a global.
+ * We should destroy everything we created through that global,
+ * and destroy the objects we created by binding to it.
+ * The identification happens by global's name, so we need to keep
+ * track what names we bound.
+ * (not implemented)
+ */
+static void
+registry_handle_global_remove(struct wthp_registry *wthp_registry,
+ uint32_t name)
+{
+ if (wthp_registry)
+ wthp_registry_free(wthp_registry);
+}
+
+static const struct wthp_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove
+};
+
+static void
+connection_handle_data(struct watch *w, uint32_t events)
+{
+ struct waltham_display *dpy = wl_container_of(w, dpy, conn_watch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ int ret;
+
+
+ if (!dpy->running) {
+ weston_log("This server is not running yet. %s:%s\n", remote->addr, remote->port);
+ return;
+ }
+
+ if (events & EPOLLERR) {
+ weston_log("Connection errored out.\n");
+ dpy->running = false;
+ remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING;
+ return;
+ }
+
+ if (events & EPOLLOUT) {
+ /* Flush out again. If the flush completes, stop
+ * polling for writable as everything has been written.
+ */
+ ret = wth_connection_flush(dpy->connection);
+ }
+
+ if (events & EPOLLIN) {
+ /* Do not ignore EPROTO */
+ ret = wth_connection_read(dpy->connection);
+
+ if (ret < 0) {
+ weston_log("Connection read error %s:%s\n", remote->addr, remote->port);
+ perror("Connection read error\n");
+ dpy->running = false;
+ remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING;
+ perror("EPOLL_CTL_DEL\n");
+ return;
+ }
+ }
+
+ if (events & EPOLLHUP) {
+ weston_log("Connection hung up.\n");
+ dpy->running = false;
+ remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING;
+
+ return;
+ }
+}
+
+static int
+waltham_mainloop(int fd, uint32_t mask, void *data)
+{
+ struct weston_transmitter_remote *remote = data;
+ struct watch *w;
+ int ret;
+ int running_display;
+ running_display = 0;
+
+ struct waltham_display *dpy = remote->display;
+ w = &dpy->conn_watch;
+ if (!dpy)
+ return -1;
+
+ if (!dpy->connection)
+ dpy->running = false;
+
+ if (!dpy->running)
+ return -1;
+
+ running_display++;
+ /* Dispatch queued events. */
+ ret = wth_connection_dispatch(dpy->connection);
+ if (ret < 0) {
+ dpy->running = false;
+ remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING;
+ }
+
+ if (!dpy->running)
+ return -1;
+
+ /* Run any application idle tasks at this point. */
+ /* (nothing to run so far) */
+
+ /* Flush out buffered requests. If the Waltham socket is
+ * full, poll it for writable too, and continue flushing then.
+ */
+ ret = wth_connection_flush(dpy->connection);
+
+ if (0 < running_display) {
+ /* Waltham events only read in the callback, not dispatched,
+ * if the Waltham socket signalled readable. If it signalled
+ * writable, flush more. See connection_handle_data().
+ */
+ w->cb(w, mask);
+ }
+
+ return 0;
+}
+
+static int
+waltham_client_init(struct waltham_display *dpy)
+{
+ if (!dpy)
+ return -1;
+ /*
+ * get server_address from controller (adrress is set to weston.ini)
+ */
+ dpy->connection = wth_connect_to_server(dpy->remote->addr, dpy->remote->port);
+ if(!dpy->connection) {
+ return -2;
+ }
+ else {
+ dpy->remote->status = WESTON_TRANSMITTER_CONNECTION_READY;
+ wl_signal_emit(&dpy->remote->connection_status_signal, dpy->remote);
+ }
+
+ dpy->conn_watch.display = dpy;
+ dpy->conn_watch.cb = connection_handle_data;
+ dpy->conn_watch.fd = wth_connection_get_fd(dpy->connection);
+ dpy->remote->source = wl_event_loop_add_fd(dpy->remote->transmitter->loop,
+ dpy->conn_watch.fd,
+ WL_EVENT_READABLE,
+ waltham_mainloop, dpy->remote);
+
+ dpy->display = wth_connection_get_display(dpy->connection);
+ /* wth_display_set_listener() is already done by waltham, as
+ * all the events are just control messaging.
+ */
+
+ /* Create a registry so that we will get advertisements of the
+ * interfaces implemented by the server.
+ */
+ dpy->registry = wth_display_get_registry(dpy->display);
+ wthp_registry_set_listener(dpy->registry, &registry_listener, dpy);
+
+ /* Roundtrip ensures all globals' ads have been received. */
+ if (wth_connection_roundtrip(dpy->connection) < 0) {
+ weston_log("Roundtrip failed.\n");
+ return -1;
+ }
+
+ if (!dpy->compositor) {
+ weston_log("Did not find wthp_compositor, quitting.\n");
+ return -1;
+ }
+
+ dpy->running = true;
+ weston_log("waltham_client_init()\n");
+
+ return 0;
+}
+
+static int
+establish_timer_handler(void *data)
+{
+ struct weston_transmitter_remote *remote = data;
+ int ret;
+
+ ret = waltham_client_init(remote->display);
+ if (ret == -2) {
+ wl_event_source_timer_update(remote->establish_timer,
+ ESTABLISH_CONNECTION_PERIOD);
+ return 0;
+ }
+
+ weston_log("establish_timer_handler()\n");
+
+ remote->status = WESTON_TRANSMITTER_CONNECTION_READY;
+ wl_signal_emit(&remote->connection_status_signal, remote);
+ return 0;
+}
+
+static void
+init_globals(struct waltham_display *dpy)
+{
+ dpy->compositor = NULL;
+ dpy->blob_factory = NULL;
+ dpy->seat = NULL;
+ dpy->application = NULL;
+ dpy->pointer = NULL;
+ dpy->keyboard = NULL;
+ dpy->touch = NULL;
+}
+
+static void
+disconnect_surface(struct weston_transmitter_remote *remote)
+{
+ struct weston_transmitter_surface *txs;
+
+ wl_list_for_each(txs, &remote->surface_list, link) {
+ free(txs->wthp_ivi_surface);
+ txs->wthp_ivi_surface = NULL;
+ free(txs->wthp_surf);
+ txs->wthp_surf = NULL;
+ }
+}
+
+static int
+retry_timer_handler(void *data)
+{
+ struct weston_transmitter_remote *remote = data;
+ struct waltham_display *dpy = remote->display;
+
+ weston_log("retry_timer_handler()\n");
+
+ if (!dpy->running) {
+ registry_handle_global_remove(dpy->registry, 1);
+ init_globals(dpy);
+ disconnect_surface(remote);
+ wl_event_source_timer_update(remote->establish_timer,
+ ESTABLISH_CONNECTION_PERIOD);
+ return 0;
+ } else {
+ wl_event_source_timer_update(remote->retry_timer,
+ RETRY_CONNECTION_PERIOD);
+ }
+
+ return 0;
+}
+
+static struct weston_transmitter_remote *
+transmitter_connect_to_remote(struct weston_transmitter *txr)
+{
+ struct weston_transmitter_remote *remote;
+ struct wl_event_loop *loop_est, *loop_retry;
+
+ wl_list_for_each_reverse(remote, &txr->remote_list, link) {
+ /* XXX: actually start connecting */
+ /* waltham */
+ remote->display = zalloc(sizeof *remote->display);
+ if (!remote->display) {
+ weston_log("Failed to allocate remote display\n");
+ return NULL;
+ }
+
+ remote->display->remote = remote;
+
+ weston_log("transmitter_connect_to_remote() for remote %p\n", remote);
+
+ /* set connection establish timer */
+ loop_est = wl_display_get_event_loop(txr->compositor->wl_display);
+ remote->establish_timer =
+ wl_event_loop_add_timer(loop_est, establish_timer_handler, remote);
+ wl_event_source_timer_update(remote->establish_timer, 1);
+
+ /* set connection retry timer */
+ loop_retry = wl_display_get_event_loop(txr->compositor->wl_display);
+ remote->retry_timer =
+ wl_event_loop_add_timer(loop_retry, retry_timer_handler, remote);
+ wl_signal_emit(&remote->conn_establish_signal, NULL);
+ }
+
+ return remote;
+}
+
+static enum weston_transmitter_connection_status
+transmitter_remote_get_status(struct weston_transmitter_remote *remote)
+{
+ return remote->status;
+}
+
+static void
+transmitter_remote_destroy(struct weston_transmitter_remote *remote)
+{
+ struct weston_transmitter_surface *txs;
+ struct weston_transmitter_output *output, *otmp;
+ struct weston_transmitter_seat *seat, *stmp;
+
+ /* Do not emit connection_status_signal. */
+
+ /*
+ * Must not touch remote->transmitter as it may be stale: the
+ * destruction order between the shell and Transmitter is undefined.
+ */
+
+ if (!wl_list_empty(&remote->surface_list))
+ weston_log("Transmitter warning: surfaces remain in %s.\n", __func__);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ txs->remote = NULL;
+
+ wl_list_remove(&remote->surface_list);
+
+ wl_list_for_each_safe(seat, stmp, &remote->seat_list, link)
+ transmitter_seat_destroy(seat);
+
+ wl_list_for_each_safe(output, otmp, &remote->output_list, link)
+ transmitter_output_destroy(output);
+
+ free(remote->addr);
+ wl_list_remove(&remote->link);
+
+ wl_event_source_remove(remote->source);
+
+ free(remote);
+}
+
+/** Transmitter is destroyed on compositor shutdown. */
+static void
+transmitter_compositor_destroyed(struct wl_listener *listener, void *data)
+{
+ struct weston_transmitter_remote *remote;
+ struct weston_transmitter_surface *txs;
+ struct weston_transmitter *txr =
+ wl_container_of(listener, txr, compositor_destroy_listener);
+
+ assert(data == txr->compositor);
+
+ /* may be called before or after shell cleans up */
+ wl_list_for_each(remote, &txr->remote_list, link) {
+ wl_list_for_each(txs, &remote->surface_list, link) {
+ transmitter_surface_zombify(txs);
+ }
+ }
+
+ /*
+ * Remove the head in case the list is not empty, to avoid
+ * transmitter_remote_destroy() accessing freed memory if the shell
+ * cleans up after Transmitter.
+ */
+ wl_list_remove(&txr->remote_list);
+
+ free(txr);
+}
+
+static struct weston_transmitter *
+transmitter_get(struct weston_compositor *compositor)
+{
+ struct wl_listener *listener;
+ struct weston_transmitter *txr;
+
+ listener = wl_signal_get(&compositor->destroy_signal,
+ transmitter_compositor_destroyed);
+ if (!listener)
+ return NULL;
+
+ txr = wl_container_of(listener, txr, compositor_destroy_listener);
+ assert(compositor == txr->compositor);
+
+ return txr;
+}
+
+static void
+transmitter_register_connection_status(struct weston_transmitter *txr,
+ struct wl_listener *connected_listener)
+{
+ wl_signal_add(&txr->connected_signal, connected_listener);
+}
+
+static struct weston_surface *
+transmitter_get_weston_surface(struct weston_transmitter_surface *txs)
+{
+ return txs->surface;
+}
+
+static struct weston_transmitter_remote *
+transmitter_get_transmitter_remote(const char *output_transmitter_name, struct weston_transmitter *transmitter)
+{
+
+ struct weston_transmitter_remote *trans_remote;
+
+ if (!output_transmitter_name)
+ return NULL;
+
+ wl_list_for_each(trans_remote, &transmitter->remote_list, link) {
+ struct weston_transmitter_output *trans_output;
+ wl_list_for_each(trans_output, &trans_remote->output_list, link) {
+ const char *name = trans_output->base.name;
+
+ if (name && !strcmp(output_transmitter_name, name))
+ return trans_remote;
+
+ name = trans_output->name;
+ if (name && !strcmp(output_transmitter_name, name))
+ return trans_remote;
+ }
+ }
+
+ return NULL;
+}
+
+static const struct weston_transmitter_api transmitter_api_impl = {
+ transmitter_get,
+ transmitter_connect_to_remote,
+ transmitter_remote_get_status,
+ transmitter_remote_destroy,
+ transmitter_surface_push_to_remote,
+ transmitter_surface_get_stream_status,
+ transmitter_surface_destroy,
+ transmitter_surface_configure,
+ transmitter_surface_gather_state,
+ transmitter_register_connection_status,
+ transmitter_get_weston_surface,
+ transmitter_get_transmitter_remote,
+};
+
+static void
+transmitter_surface_set_resize_callback(
+ struct weston_transmitter_surface *txs,
+ weston_transmitter_ivi_resize_handler_t cb,
+ void *data)
+{
+ txs->resize_handler = cb;
+ txs->resize_handler_data = data;
+}
+
+static void
+_transmitter_surface_set_ivi_id(struct weston_transmitter_surface *txs, uint32_t ivi_id)
+{
+
+}
+
+static const struct weston_transmitter_ivi_api transmitter_ivi_api_impl = {
+ _transmitter_surface_set_ivi_id,
+ transmitter_surface_set_resize_callback,
+};
+
+static int
+transmitter_create_remote(struct weston_transmitter *txr,
+ const char *model,
+ const char *addr,
+ const char *port,
+ const char *width,
+ const char *height)
+{
+ struct weston_transmitter_remote *remote;
+
+ remote = zalloc(sizeof (*remote));
+ if (!remote)
+ return -1;
+
+ remote->transmitter = txr;
+ wl_list_insert(&txr->remote_list, &remote->link);
+
+ remote->model = strdup(model);
+ remote->addr = strdup(addr);
+ remote->port = strdup(port);
+ if (remote->width)
+ remote->width = atoi(width);
+ if (remote->height)
+ remote->height = atoi(height);
+ remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING;
+
+ weston_log("Creating transmitter remote output model %s, addr %s, "
+ "port %s, width %d, height %d, status %d\n",
+ remote->model, remote->addr, remote->port, remote->width,
+ remote->height, remote->status);
+
+ wl_signal_init(&remote->connection_status_signal);
+
+ wl_list_init(&remote->output_list);
+ wl_list_init(&remote->surface_list);
+ wl_list_init(&remote->seat_list);
+
+ wl_signal_init(&remote->conn_establish_signal);
+ remote->establish_listener.notify = conn_ready_notify;
+ wl_signal_add(&remote->conn_establish_signal, &remote->establish_listener);
+
+ return 0;
+}
+
+struct wet_compositor {
+ struct weston_config *config;
+ struct wet_output_config *parsed_options;
+ struct wl_listener pending_output_listener;
+ bool drm_use_current_mode;
+};
+
+static int
+load_config(struct weston_config **config, bool no_config,
+ const char *config_file)
+{
+ const char *file = "agl-compositor.ini";
+ const char *full_path;
+
+ if (config_file)
+ file = config_file;
+
+ if (!no_config)
+ *config = weston_config_parse(file);
+
+ if (*config) {
+ full_path = weston_config_get_full_path(*config);
+
+ weston_log("Using config file '%s'.\n", full_path);
+ setenv(WESTON_CONFIG_FILE_ENV_VAR, full_path, 1);
+
+ return 0;
+ }
+
+ if (config_file && !no_config) {
+ weston_log("fatal: error opening or reading config file '%s'.\n",
+ config_file);
+
+ return -1;
+ }
+
+ weston_log("Starting with no config file.\n");
+ setenv(WESTON_CONFIG_FILE_ENV_VAR, "", 1);
+
+ return 0;
+}
+
+
+static void
+transmitter_get_server_config(struct weston_transmitter *txr)
+{
+ struct weston_config *config = NULL;
+ struct weston_config_section *section;
+ const char *name = NULL;
+ char *model = NULL;
+ char *addr = NULL;
+ char *port = NULL;
+ char *width = NULL;
+ char *height = NULL;
+ int ret;
+
+ /* FIXME: this assume as hard-coded agl-compositor */
+ if (load_config(&config, 0, "agl-compositor.ini") < 0)
+ return;
+
+ section = weston_config_get_section(config, "remote", NULL, NULL);
+
+ while (weston_config_next_section(config, &section, &name)) {
+ if (0 == strcmp(name, "transmitter-output")) {
+ if (0 != weston_config_section_get_string(section, "name",
+ &model, 0))
+ continue;
+
+ if (0 != weston_config_section_get_string(section, "host",
+ &addr, 0))
+ continue;
+
+ if (0 != weston_config_section_get_string(section, "port",
+ &port, 0))
+ continue;
+
+ ret = transmitter_create_remote(txr, model, addr,
+ port, width, height);
+ if (ret < 0) {
+ weston_log("Fatal: Transmitter create_remote failed.\n");
+ }
+ }
+ }
+}
+
+WL_EXPORT int
+wet_module_init(struct weston_compositor *compositor, int *argc, char *argv[])
+{
+ struct weston_transmitter *txr;
+ int ret;
+
+ txr = zalloc(sizeof *txr);
+ if (!txr){
+ weston_log("Transmitter disabled\n");
+ return -1;
+ }
+ wl_list_init(&txr->remote_list);
+
+ txr->compositor = compositor;
+ txr->compositor_destroy_listener.notify =
+ transmitter_compositor_destroyed;
+ wl_signal_add(&compositor->destroy_signal,
+ &txr->compositor_destroy_listener);
+
+ ret = weston_plugin_api_register(compositor,
+ WESTON_TRANSMITTER_API_NAME,
+ &transmitter_api_impl,
+ sizeof(transmitter_api_impl));
+ if (ret < 0) {
+ weston_log("Fatal: Transmitter API registration failed.\n");
+ goto fail;
+ }
+
+ ret = weston_plugin_api_register(compositor,
+ WESTON_TRANSMITTER_IVI_API_NAME,
+ &transmitter_ivi_api_impl,
+ sizeof(transmitter_ivi_api_impl));
+ if (ret < 0) {
+ weston_log("Fatal: Transmitter IVI API registration failed.\n");
+ goto fail;
+ }
+
+ weston_log("Transmitter initialized.\n");
+
+ txr->loop = wl_display_get_event_loop(compositor->wl_display);
+ transmitter_get_server_config(txr);
+ transmitter_connect_to_remote(txr);
+
+ return 0;
+
+fail:
+ wl_list_remove(&txr->compositor_destroy_listener.link);
+ free(txr);
+
+ return -1;
+}
diff --git a/transmitter-plugin/weston.ini.transmitter b/transmitter-plugin/weston.ini.transmitter
new file mode 100644
index 0000000..0d5efe9
--- /dev/null
+++ b/transmitter-plugin/weston.ini.transmitter
@@ -0,0 +1,13 @@
+[transmitter-output]
+name=transmitter_1
+mode=800x600@60
+host=192.168.100.9
+port=34400
+agl-shell-app-id=weston-simple-egl
+
+[transmitter-output]
+name=transmitter_2
+mode=800x600@60
+host=192.168.100.9
+port=34401
+agl-shell-app-id=weston-simple-shm