transmitter: initial commit for waltham-transmitter 31/15131/2
authorWataru Mizuno <wmizuno@jp.adit-jv.com>
Mon, 9 Jul 2018 09:14:05 +0000 (18:14 +0900)
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>
Fri, 27 Jul 2018 10:51:25 +0000 (10:51 +0000)
The waltham-transmitter is the plugin of weston to enable
client applications to share surface between multiple domains.

Change-Id: I691410f5b6e74fa981ae53201b728810373185a2
Signed-off-by: Wataru Mizuno <wmizuno@jp.adit-jv.com>
14 files changed:
CMakeLists.txt [new file with mode: 0644]
waltham-transmitter/CMakeLists.txt [new file with mode: 0644]
waltham-transmitter/COPYING [new file with mode: 0644]
waltham-transmitter/transmitter-plugin/CMakeLists.txt [new file with mode: 0644]
waltham-transmitter/transmitter-plugin/README [new file with mode: 0644]
waltham-transmitter/transmitter-plugin/input.c [new file with mode: 0644]
waltham-transmitter/transmitter-plugin/output.c [new file with mode: 0644]
waltham-transmitter/transmitter-plugin/plugin.c [new file with mode: 0644]
waltham-transmitter/transmitter-plugin/plugin.h [new file with mode: 0644]
waltham-transmitter/transmitter-plugin/transmitter_api.h [new file with mode: 0644]
waltham-transmitter/transmitter-plugin/weston.ini.transmitter [new file with mode: 0644]
waltham-transmitter/waltham-renderer/CMakeLists.txt [new file with mode: 0644]
waltham-transmitter/waltham-renderer/waltham-renderer.c [new file with mode: 0644]
waltham-transmitter/waltham-renderer/waltham-renderer.h [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..00fd14e
--- /dev/null
@@ -0,0 +1,3 @@
+project (weston-ivi-plugins)
+
+add_subdirectory(waltham-transmitter)
diff --git a/waltham-transmitter/CMakeLists.txt b/waltham-transmitter/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b4d1243
--- /dev/null
@@ -0,0 +1,4 @@
+project (transmitter)
+
+add_subdirectory(transmitter-plugin)
+add_subdirectory(waltham-renderer)
diff --git a/waltham-transmitter/COPYING b/waltham-transmitter/COPYING
new file mode 100644 (file)
index 0000000..d65f5d3
--- /dev/null
@@ -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/waltham-transmitter/transmitter-plugin/CMakeLists.txt b/waltham-transmitter/transmitter-plugin/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a900d3b
--- /dev/null
@@ -0,0 +1,62 @@
+project (transmitter)
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(WAYLAND_SERVER wayland-server>=1.13.0 REQUIRED)
+pkg_check_modules(WESTON weston>=2.0.0 REQUIRED)
+pkg_check_modules(PIXMAN pixman-1 REQUIRED)
+pkg_check_modules(WALTHAM waltham REQUIRED)
+
+include_directories(
+    include
+    ${CMAKE_SOURCE_DIR}/waltham-transmitter/waltham-renderer
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${WAYLAND_CLIENT_INCLUDE_DIRS}
+    ${WAYLAND_SERVER_INCLUDE_DIRS}
+    ${WESTON_INCLUDE_DIRS}
+    ${PIXMAN_INCLUDE_DIRS}
+    ${WALTHAM_INCLUDE_DIRS}
+)
+
+link_directories(
+    ${WAYLAND_SERVER_LIBRARY_DIRS}
+    ${WESTON_LIBRARY_DIRS}
+    ${PIXMAN_LIBRARY_DIRS}
+    ${WALTHAM_LIBRARY_DIRS}
+)
+
+add_library(${PROJECT_NAME} MODULE
+    plugin.c
+    output.c
+    input.c
+    plugin.h
+    transmitter_api.h
+)
+
+set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
+
+set(LIBS
+    m
+    ${WAYLAND_SERVER_LIBRARIES}
+    ${WESTON_LIBRARIES}
+    ${PIXMAN_LIBRARIES}
+    ${WALTHAM_LIBRARIES}
+)
+
+SET(SRC_FILES
+    plugin.c
+    output.c
+    input.c
+    plugin.h
+    transmitter_api.h
+)
+
+
+
+add_dependencies(${PROJECT_NAME} ${LIBS})
+
+target_link_libraries(${PROJECT_NAME} ${LIBS})
+
+install (
+    TARGETS             ${PROJECT_NAME}
+    LIBRARY DESTINATION lib64/weston
+)
diff --git a/waltham-transmitter/transmitter-plugin/README b/waltham-transmitter/transmitter-plugin/README
new file mode 100644 (file)
index 0000000..345142d
--- /dev/null
@@ -0,0 +1,97 @@
+Transmitter plugin
+
+The current implementation of Transmitter is a stub which interfaces to
+other Weston parts appropriately, but all networking is just a mockup.
+
+Sections in this file describe:
+- How to build
+- How to write weston.ini
+- How to test
+
+How to build
+============
+Configure Weston with --enable-surface-remoting to build the Transmitter
+plugin.
+
+How to write weston.ini
+=======================
+To load transmitter plugin to weston, add 'transmitter.so' to the 'modules'
+key under '[core]', and make sure the 'shell' is 'ivi-shell.so'.
+
+The destination of remoting is configured in weston.ini.
+Add output name, server address, port number, output's width and height key
+under '[remote-output]'.
+You can speficy multiple [remote-output].
+
+In details, see 'weston.ini.transmitter'.
+
+How to test
+===========
+You can use server side test application in waltham-server directory.
+
+If you set 'WALTHAM_DEBUG=1' to your environment valuable, you can
+see the log like this:
+
+ [13:24:08.345] Loading module '/usr/lib64/weston/transmitter.so'
+ [13:24:08.345] Registered plugin API 'transmitter_v1' of size 88
+ [13:24:08.345] Registered plugin API 'transmitter_ivi_v1' of size 16
+ [13:24:08.345] Transmitter initialized.
+ [13:24:08.345] Loading module '/usr/lib64/libweston-2/waltham-renderer.so'
+ [13:24:08.352] gst-setting are :-->
+ [13:24:08.352] ip = 192.168.2.52
+ [13:24:08.352] port = 34400
+ [13:24:08.352] bitrate = 3000000
+ [13:24:08.352] crop = 384 x 368
+ [13:24:08.352] width = 1920
+ [13:24:08.352] width = 1080
+ [13:24:08.531] open media device: platform:fe960000.vsp (fe960000.vsp)
+ [13:24:08.532] input pad setup ('fe960000.vsp rpf.0 input':'/dev/video0')
+ [13:24:08.533] output pad setup (fe960000.vsp wpf.0 output:/dev/video5)
+ [13:24:08.533] vsp-device '/dev/media0' created
+ [13:24:08.533] gst_recorder_create (1920x1080) crop 384x368 at 0,0
+ [13:24:08.533] gst_pipeline: starting: appsrc name=src ! omxh264enc target-bitrate=3000000 control-rate=2 no-copy=k
+ [13:24:08.582] goot 1 pools
+ [13:24:08.583]  pool settings size 211968, min 5, max 5
+ [13:24:08.583] gst_recorder_create done
+ [13:24:08.583] [gst recorder] transmitter-192.168.2.52:34400-1: recorder initialized
+ [13:24:08.583] Transmitter weston_seat 0x15424630
+ [13:24:08.583] Transmitter created pointer=0x15625df0 for seat 0x15424630
+ [13:24:08.583] Transmitter created keyboard=0x154247c0 for seat 0x15424630
+ [13:24:08.583] Transmitter created touch=0x15625f10 for seat 0x15424630
+
+The connection is established, you can see following debug messages:
+
+ debug: wth_connection_insert_new_object: new object id: 1
+ debug: wth_connection_insert_new_object: new object id: 2
+ 2018-01-09T13:24:22Z 00001000030000000100000002000000 wth_display_get_registry
+ debug: wth_connection_insert_new_object: new object id: 3
+ 2018-01-09T13:24:22Z 00001000020000000100000003000000 wth_display_sync
+ debug: Message received on conn 0x15572730: (9) 40 bytes
+ debug: wthp_registry_send_global(2, 1, [variable type const char *], 4) (opcode 9) called.
+ debug: wth_connection_insert_new_object: new object id: 4
+ 2018-01-09T13:24:22Z 00002c000800000002000000010000000400000010000000777468705f636f6d706f7369746f720001000000 wthpd
+ debug: Message received on conn 0x15572730: (9) 48 bytes
+ debug: wthp_registry_send_global(2, 1, [variable type const char *], 1) (opcode 9) called.
+ debug: wth_connection_insert_new_object: new object id: 5
+ 2018-01-09T13:24:22Z 000034000800000002000000010000000500000015000000777468705f6976695f6170706c69636174696f6e00010d
+ debug: Message received on conn 0x15572730: (9) 44 bytes
+ debug: wthp_registry_send_global(2, 1, [variable type const char *], 4) (opcode 9) called.
+ debug: wth_connection_insert_new_object: new object id: 6
+ 2018-01-09T13:24:22Z 000030000800000002000000010000000600000012000000777468705f626c6f625f666163746f72790001000000 d
+ debug: Message received on conn 0x15572730: (9) 36 bytes
+ debug: wthp_registry_send_global(2, 1, [variable type const char *], 4) (opcode 9) called.
+ debug: wth_connection_insert_new_object: new object id: 7
+ 2018-01-09T13:24:22Z 00002800080000000200000001000000070000000a000000777468705f736561740001000000 wthp_registry_bid
+ debug: Message received on conn 0x15572730: (11) 16 bytes
+ debug: wthp_callback_send_done(3, 0) (opcode 11) called.
+
+Start remoting :
+- Start an IVI application.
+- Put surface on transmitter output
+
+Weston log will indicate remoting has started:
+
+[13:18:24.572] HMI transmitting surface 0x1c3dad0, ivi-id 0x9ff6
+[13:18:24.572] Transmitter: update surface 0x1c3dad0 (0, 0), 0 cb
+[13:18:24.572] transmitter_surface_set_ivi_id(0x1c3dad0, 0x9ff6)
+[13:18:24.972] Transmitter: surface 0x1c3dad0 entered output transmitter-0.0.0.0:66-1
\ No newline at end of file
diff --git a/waltham-transmitter/transmitter-plugin/input.c b/waltham-transmitter/transmitter-plugin/input.c
new file mode 100644 (file)
index 0000000..e00546b
--- /dev/null
@@ -0,0 +1,1317 @@
+/*
+ * 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 "compositor.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,
+                           uint32_t 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,
+                           uint32_t 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,
+                         uint32_t 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,
+                 uint32_t 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,
+                       uint32_t time,
+                       int touch_id,
+                       wl_fixed_t x,
+                       wl_fixed_t y)
+{
+}
+
+static void
+touch_grab_up_handler(struct weston_touch_grab *grab,
+                     uint32_t time,
+                     int touch_id)
+{
+}
+
+static void
+touch_grab_motion_handler(struct weston_touch_grab *grab,
+                         uint32_t 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,
+};
+
+
+/* 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.
+ */
+static 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 wl_client *client;
+       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);
+       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;
+
+       time = weston_compositor_get_time();
+
+       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/waltham-transmitter/transmitter-plugin/output.c b/waltham-transmitter/transmitter-plugin/output.c
new file mode 100644 (file)
index 0000000..c379ce5
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * 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>
+
+#include "compositor.h"
+#include "compositor-drm.h"
+#include "plugin-registry.h"
+
+#include "plugin.h"
+#include "transmitter_api.h"
+#include "waltham-renderer.h"
+
+/** @file
+ *
+ * This is an implementation of a remote output.
+ *
+ * A remote output must not be accepted as an argument to:
+ * - wl_shell_surface.set_fullscreen
+ * - wl_shell_surface.set_maximized
+ * - zwp_fullscreen_shell_v1.present_surface
+ * - zwp_fullscreen_shell_v1.present_surface_for_mode
+ * - zwp_input_panel_surface_v1.set_toplevel
+ * - xdg_surface.set_fullscreen
+ *
+ * If a remote output is an argument to the above or similar requests,
+ * it should have the same effect as NULL if possible.
+ *
+ * @todo Should we instead accept the argument and have it start remoting
+ * automatically? That would be shell-specific.
+ *
+ * In ivi-shell's case, only zwp_input_panel_surface_v1.set_toplevel is
+ * reachable from keyboard.c. That just blindly uses whatever the first
+ * output happens to be, so there is no need to check for now.
+ *
+ * @todo Add weston_output_set_remote() which sets weston_output::is_remote
+ * to true and inits weston_output::link. This should be made mutually
+ * exclusive with weston_compositor_add_output().
+ */
+
+static struct waltham_renderer_interface *waltham_renderer;
+
+static char *
+make_model(struct weston_transmitter_remote *remote, int name)
+{
+       char *str;
+
+       if (asprintf(&str, "transmitter-%s:%s-%d", remote->addr, remote->port, name) < 0)
+               return NULL;
+
+       return str;
+}
+
+static int
+make_mode_list(struct wl_list *list,
+              const struct weston_transmitter_output_info *info)
+{
+       struct weston_mode *mode;
+
+       mode = zalloc(sizeof *mode);
+       if (!mode)
+               return -1;
+
+       *mode = info->mode;
+       wl_list_insert(list->prev, &mode->link);
+
+       return 0;
+}
+
+static struct weston_mode *
+get_current_mode(struct wl_list *mode_list)
+{
+       struct weston_mode *mode;
+
+       wl_list_for_each(mode, mode_list, link)
+               if (mode->flags & WL_OUTPUT_MODE_CURRENT)
+                       return mode;
+
+       assert(0);
+       return NULL;
+}
+
+static void
+free_mode_list(struct wl_list *mode_list)
+{
+       struct weston_mode *mode;
+
+       while (!wl_list_empty(mode_list)) {
+               mode = wl_container_of(mode_list->next, mode, link);
+
+               wl_list_remove(&mode->link);
+               free(mode);
+       }
+}
+
+void
+transmitter_output_destroy(struct weston_transmitter_output *output)
+{
+       wl_list_remove(&output->link);
+
+       free_mode_list(&output->base.mode_list);
+       free(output->base.serial_number);
+       free(output->base.model);
+       free(output->base.make);
+
+       weston_output_destroy(&output->base);
+       free(output);
+}
+
+static void
+transmitter_output_destroy_(struct weston_output *base)
+{
+       struct weston_transmitter_output *output = wl_container_of(base, output, base);
+
+       transmitter_output_destroy(output);
+}
+
+
+static void
+transmitter_start_repaint_loop(struct weston_output *base)
+{
+       struct timespec ts;
+       struct weston_transmitter_output *output = wl_container_of(base, output, base);
+
+       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
+       weston_output_finish_frame(&output->base, &ts, 0);
+}
+
+static int
+transmitter_output_repaint(struct weston_output *base,
+                          pixman_region32_t *damage)
+{
+       struct weston_transmitter_output* output = wl_container_of(base, output, base);
+       struct weston_transmitter_remote* remote = output->remote;
+       struct weston_transmitter* txr = remote->transmitter;
+       struct weston_transmitter_api* transmitter_api =
+               weston_get_transmitter_api(txr->compositor);
+       struct weston_transmitter_surface* txs;
+       struct weston_compositor *compositor = base->compositor;
+       struct weston_view *view;
+       bool found_output = false;
+       struct timespec ts;
+
+       struct weston_drm_output_api *api =
+               weston_plugin_api_get(txr->compositor,  WESTON_DRM_OUTPUT_API_NAME, sizeof(api));
+
+       /*
+        * Pick up weston_view in transmitter_output and check weston_view's surface
+        * If the surface hasn't been conbined to weston_transmitter_surface,
+        * then call push_to_remote.
+        * If the surface has already been combined, call gather_state.
+        */
+       if (wl_list_empty(&compositor->view_list))
+               goto out;
+
+       if (remote->status == WESTON_TRANSMITTER_CONNECTION_DISCONNECTED)
+               goto out;
+
+       wl_list_for_each_reverse(view, &compositor->view_list, link) {
+               bool found_surface = false;
+               if (view->output == &output->base) {
+                       found_output = true;
+                       wl_list_for_each(txs, &remote->surface_list, link) {
+                               if (txs->surface == view->surface) {
+                                       found_surface = true;
+                                       if (!txs->wthp_surf)
+                                               transmitter_api->surface_push_to_remote
+                                                       (view->surface, remote, NULL);
+
+                                       output->renderer->dmafd =
+                                               api->get_dma_fd_from_view(&output->base, view);
+                                       if(!output->renderer->dmafd) {
+                                               weston_log("Failed to get dmafd\n");
+                                               goto out;
+                                       }
+
+                                       /*
+                                        * Updating the width x height
+                                        * from surface to gst-recorder
+                                        */
+                                       output->renderer->surface_width
+                                               = view->surface->width;
+                                       output->renderer->surface_height
+                                               = view->surface->height;
+
+                                       output->renderer->repaint_output(output);
+                                       output->renderer->dmafd = NULL;
+                                       transmitter_api->surface_gather_state(txs);
+                                       weston_buffer_reference(&view->surface->buffer_ref, NULL);
+                                       break;
+                               }
+                       }
+                       if (!found_surface)
+                               transmitter_api->surface_push_to_remote(view->surface,
+                                                                       remote, NULL);
+               }
+       }
+       if (!found_output)
+               goto out;
+
+       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
+       weston_output_finish_frame(&output->base, &ts, 0);
+
+       return 0;
+
+out:
+       transmitter_start_repaint_loop(base);
+
+       return 0;
+}
+
+static void
+transmitter_assign_planes(struct weston_output *base) {
+       /*
+        * This function prevents compositor releasing buffer early.
+        */
+       struct weston_transmitter_output* output = wl_container_of(base, output, base);
+       struct weston_transmitter_remote* remote = output->remote;
+       struct weston_transmitter_surface* txs;
+       struct weston_compositor *compositor = base->compositor;
+       struct weston_view *view;
+
+       wl_list_for_each_reverse(view, &compositor->view_list, link) {
+               if (view->output == &output->base) {
+                       wl_list_for_each(txs, &remote->surface_list, link) {
+                               if (txs->surface == view->surface)
+                                       view->surface->keep_buffer = true;
+
+                       }
+               }
+       }
+}
+
+static void
+transmitter_output_enable(struct weston_output *base)
+{
+       struct weston_transmitter_output *output = wl_container_of(base, output, base);
+
+       output->base.assign_planes = transmitter_assign_planes;
+       output->base.set_backlight = NULL;
+       output->base.set_dpms = NULL;
+       output->base.switch_mode = NULL;
+}
+
+int
+transmitter_remote_create_output(struct weston_transmitter_remote *remote,
+                                const struct weston_transmitter_output_info *info)
+{
+       struct weston_transmitter_output *output;
+       struct weston_transmitter *txr = remote->transmitter;
+       struct weston_output *def_output;
+
+       output = zalloc(sizeof *output);
+       if (!output)
+               return -1;
+
+       output->parent.draw_initial_frame = true;
+
+       output->base.subpixel = info->subpixel;
+
+       output->base.name = make_model(remote, 1);
+       output->base.make = strdup(WESTON_TRANSMITTER_OUTPUT_MAKE);
+       output->base.model = make_model(remote, 1);
+       output->base.serial_number = strdup("0");
+       /* x and y is fake value */
+       wl_list_init(&output->base.mode_list);
+       if (make_mode_list(&output->base.mode_list, info) < 0)
+               goto fail;
+
+       output->base.current_mode = get_current_mode(&output->base.mode_list);
+       output->base.height = output->base.current_mode->height;
+       output->base.width = output->base.current_mode->width;
+       /* WL_OUTPUT_MODE_CURRENT already set */
+       weston_output_init(&output->base, remote->transmitter->compositor);
+
+       /*
+        * renderer_output_create skipped:
+        * no renderer awareness is needed for this output
+        */
+
+       /*
+        * weston_compositor_add_output() skipped:
+        * Most other code uses weston_compositor::output_list when traversing
+        * all outputs, we do not want any of that.
+        * Also weston_compositor::output_created_signal must not trigger
+        * for this output, since we must not involve input device management
+        * or color management or any kind of local management.
+        */
+       output->base.enable = transmitter_output_enable;
+       output->base.start_repaint_loop = transmitter_start_repaint_loop;
+       output->base.repaint = transmitter_output_repaint;
+       output->base.destroy = transmitter_output_destroy_;
+       output->base.assign_planes = NULL;
+       output->base.set_dpms = NULL;
+       output->base.switch_mode = NULL;
+       output->base.gamma_size = 0;
+       output->base.set_gamma = NULL;
+
+       output->base.native_mode = output->base.current_mode;
+       output->base.native_scale = output->base.current_scale;
+       output->base.scale = 1;
+       output->base.transform = WL_OUTPUT_TRANSFORM_NORMAL;
+
+       output->remote = remote;
+       wl_list_insert(&remote->output_list, &output->link);
+
+       /* Loading a waltham renderer library */
+       waltham_renderer = weston_load_module("waltham-renderer.so","waltham_renderer_interface");
+
+       if (waltham_renderer->display_create(output) < 0) {
+               weston_log("Failed to create waltham renderer display \n");
+               return -1;
+       }
+
+       weston_output_enable(&output->base);
+
+       return 0;
+
+fail:
+       free_mode_list(&output->base.mode_list);
+       free(output->base.serial_number);
+       free(output->base.model);
+       free(output->base.make);
+       free(output->base.name);
+       free(output);
+
+       return -1;
+}
diff --git a/waltham-transmitter/transmitter-plugin/plugin.c b/waltham-transmitter/transmitter-plugin/plugin.c
new file mode 100644 (file)
index 0000000..f643bd8
--- /dev/null
@@ -0,0 +1,940 @@
+/*
+ * 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>
+#include <linux/input.h>
+
+#include "compositor.h"
+
+#include "weston.h"
+#include "plugin.h"
+#include "transmitter_api.h"
+#include "plugin-registry.h"
+#include "ivi-layout-export.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
+
+/* 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
+};
+
+static void
+transmitter_surface_gather_state(struct weston_transmitter_surface *txs)
+{
+       struct weston_transmitter_remote *remote = txs->remote;
+       struct waltham_display *dpy = remote->display;
+       int ret;
+
+       if(!dpy->running) {
+               if(remote->status != WESTON_TRANSMITTER_CONNECTION_DISCONNECTED) {
+                       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 = malloc(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);
+               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);
+}
+
+static 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);
+}
+
+static void
+transmitter_surface_set_ivi_id(struct weston_transmitter_surface *txs)
+{
+        struct weston_transmitter_remote *remote = txs->remote;
+       struct waltham_display *dpy = remote->display;
+       struct weston_surface *ws;
+       struct ivi_layout_surface **pp_surface = NULL;
+       struct ivi_layout_surface *ivi_surf = NULL;
+       int32_t surface_length = 0;
+       int32_t ret = 0;
+       int32_t i = 0;
+
+       ret = txs->lyt->get_surfaces(&surface_length, &pp_surface);
+       if(!ret)
+               weston_log("No ivi_surface\n");
+
+       ws = txs->surface;
+
+       for(i = 0; i < surface_length; i++) {
+               ivi_surf = pp_surface[i];
+               if (ivi_surf->surface == ws) {
+                       assert(txs->surface);
+                       if (!txs->surface)
+                               return;
+                       if(!dpy)
+                               weston_log("no content in waltham_display\n");
+                       if(!dpy->compositor)
+                               weston_log("no content in compositor object\n");
+                       if(!dpy->seat)
+                               weston_log("no content in seat object\n");
+                       if(!dpy->application)
+                               weston_log("no content in ivi-application object\n");
+
+                       txs->wthp_ivi_surface = wthp_ivi_application_surface_create
+                               (dpy->application, ivi_surf->id_surface,  txs->wthp_surf);
+                       weston_log("surface ID %d\n", ivi_surf->id_surface);
+                       if(!txs->wthp_ivi_surface){
+                               weston_log("Failed to create txs->ivi_surf\n");
+                       }
+               }
+       }
+       free(pp_surface);
+       pp_surface = NULL;
+}
+
+static struct weston_transmitter_surface *
+transmitter_surface_push_to_remote(struct weston_surface *ws,
+                                  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)
+                       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) {
+               weston_log("txs->wthp_surf is NULL\n");
+               txs->wthp_surf = wthp_compositor_create_surface(remote->display->compositor);
+               transmitter_surface_set_ivi_id(txs);
+       }
+
+       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);
+       }
+}
+
+/* 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);
+       struct weston_transmitter_output_info info = {
+               WL_OUTPUT_SUBPIXEL_NONE,
+               WL_OUTPUT_TRANSFORM_NORMAL,
+               1,
+               0, 0,
+               300, 200,
+               strdup(remote->model),
+               {
+                       WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED,
+                       800, 600,
+                       51519,
+                       { NULL, NULL }
+               }
+       };
+       if(remote->width != 0) {
+               if(remote->height != 0) {
+                       info.mode.width = remote->width;
+                       info.mode.height = remote->height;
+               }
+       }
+       /* Outputs and seats are dynamic, do not guarantee they are all
+        * present when signalling connection status.
+        */
+       transmitter_remote_create_output(remote, &info);
+       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 void
+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)
+               goto not_running;
+
+       if (!dpy->connection)
+               dpy->running = false;
+
+       if (!dpy->running)
+               goto not_running;
+
+       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)
+               goto not_running;
+
+       /* 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);
+       }
+
+not_running:
+       ;
+}
+
+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;
+
+       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;
+       }
+       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;
+
+       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;
+       int ret;
+
+       wl_list_for_each_reverse(remote, &txr->remote_list, link) {
+               /* XXX: actually start connecting */
+               /* waltham */
+               remote->display = zalloc(sizeof *remote->display);
+               if (!remote->display)
+                       return NULL;
+               remote->display->remote = 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);
+               if (ret < 0) {
+                       weston_log("Fatal: Transmitter waltham connecting failed.\n");
+                       return NULL;
+               }
+               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 desctruction 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 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,
+};
+
+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 const struct weston_transmitter_ivi_api transmitter_ivi_api_impl = {
+       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);
+       remote->width = atoi(width);
+       remote->height = atoi(height);
+       remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING;
+       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 void
+transmitter_get_server_config(struct weston_transmitter *txr)
+{
+       struct wet_compositor *compositor =
+               (struct wet_compositor *)weston_compositor_get_user_data(txr->compositor);
+       struct weston_config *config = wet_get_config(txr->compositor);
+       struct weston_config_section *section;
+       const char *name = NULL;
+       char *model = NULL;
+       char *addr = NULL;
+       char *port = NULL;
+       char *width = '0';
+       char *height = '0';
+       int ret;
+
+       section = weston_config_get_section(config, "remote", NULL, NULL);
+
+       while (weston_config_next_section(config, &section, &name)) {
+               if (0 == strcmp(name, "remote-output")) {
+                       if (0 != weston_config_section_get_string(section, "output-name",
+                                                                 &model, 0))
+                               continue;
+
+                       if (0 != weston_config_section_get_string(section, "server-address",
+                                                                 &addr, 0))
+                               continue;
+
+                       if (0 != weston_config_section_get_string(section, "port",
+                                                                 &port, 0))
+                               continue;
+
+                       if (0 != weston_config_section_get_string(section, "width",
+                                                                 &width, 0))
+                               continue;
+
+                       if (0 != weston_config_section_get_string(section, "height",
+                                                                 &height, 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/waltham-transmitter/transmitter-plugin/plugin.h b/waltham-transmitter/transmitter-plugin/plugin.h
new file mode 100644 (file)
index 0000000..a473dab
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * 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 "compositor.h"
+#include "transmitter_api.h"
+#include "ivi-layout-export.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 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 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;
+
+       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;
+
+       struct weston_transmitter_remote *remote;
+       struct wl_list link; /* weston_transmitter_remote::output_list */
+
+       struct frame *frame;
+
+       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);
+
+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);
+
+static const struct wthp_seat_listener seat_listener = {
+       seat_capabilities,
+       NULL
+};
+
+
+#endif /* WESTON_TRANSMITTER_PLUGIN_H */
diff --git a/waltham-transmitter/transmitter-plugin/transmitter_api.h b/waltham-transmitter/transmitter-plugin/transmitter_api.h
new file mode 100644 (file)
index 0000000..9b3e5fe
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * 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 "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;
+
+#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,
+                                 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);
+};
+
+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_output *base);
+       struct GstAppContext *ctx;
+       int32_t dmafd;    /* dmafd received from compositor-drm */
+       int surface_width;
+       int surface_height;
+       bool recorder_enabled;
+};
+
+#endif /* WESTON_TRANSMITTER_API_H */
diff --git a/waltham-transmitter/transmitter-plugin/weston.ini.transmitter b/waltham-transmitter/transmitter-plugin/weston.ini.transmitter
new file mode 100644 (file)
index 0000000..1aff0b2
--- /dev/null
@@ -0,0 +1,21 @@
+[core]
+shell=ivi-shell.so
+modules=transmitter.so
+
+[ivi-shell]
+ivi-module=ivi-controller.so
+ivi-input-module=ivi-input-controller.so
+
+[remote-output]
+output-name=transmitter_1
+server-address=192.168.2.11
+port=34400
+width=1920
+height=1080
+
+[remote-output]
+output-name=transmitter_2
+server-address=192.168.2.12
+port=34400
+width=1920
+height=1080
diff --git a/waltham-transmitter/waltham-renderer/CMakeLists.txt b/waltham-transmitter/waltham-renderer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..abf1a4c
--- /dev/null
@@ -0,0 +1,59 @@
+project (waltham-renderer)
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(WAYLAND_SERVER wayland-server>=1.13.0 REQUIRED)
+pkg_check_modules(WESTON weston>=2.0.0 REQUIRED)
+pkg_check_modules(PIXMAN pixman-1 REQUIRED)
+pkg_check_modules(WALTHAM waltham REQUIRED)
+pkg_search_module(GSTREAMER gstreamer-1.0 required)
+pkg_search_module(GSTREAMERAPP gstreamer-app-1.0 required)
+
+include_directories(
+    ${CMAKE_SOURCE_DIR}/waltham-transmitter/transmitter-plugin
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${WAYLAND_CLIENT_INCLUDE_DIRS}
+    ${WAYLAND_SERVER_INCLUDE_DIRS}
+    ${WESTON_INCLUDE_DIRS}
+    ${PIXMAN_INCLUDE_DIRS}
+    ${WALTHAM_INCLUDE_DIRS}
+    ${GSTREAMER_INCLUDE_DIRS}
+    ${GSTREAMERAPP_INCLUDE_DIRS}
+)
+
+link_directories(
+    ${WAYLAND_SERVER_LIBRARY_DIRS}
+    ${WESTON_LIBRARY_DIRS}
+    ${PIXMAN_LIBRARY_DIRS}
+    ${WALTHAM_LIBRARY_DIRS}
+    ${GSTREAMER_LIBRARY_DIRS}
+    ${GSTREAMERAPP_LIBRARY_DIRS}
+)
+
+add_library(${PROJECT_NAME} MODULE
+        waltham-renderer.c
+        waltham-renderer.h
+)
+
+set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
+
+set(LIBS
+    m
+    weston-2
+    gstallocators-1.0
+    gstvideo-1.0
+    ${WAYLAND_SERVER_LIBRARIES}
+    ${WESTON_LIBRARIES}
+    ${PIXMAN_LIBRARIES}
+    ${WALTHAM_LIBRARIES}
+    ${GSTREAMER_LIBRARIES}
+    ${GSTREAMERAPP_LIBRARIES}
+)
+
+add_dependencies(${PROJECT_NAME} ${LIBS})
+
+target_link_libraries(${PROJECT_NAME} ${LIBS})
+
+install (
+    TARGETS             ${PROJECT_NAME}
+    LIBRARY DESTINATION lib64/libweston-2
+)
diff --git a/waltham-transmitter/waltham-renderer/waltham-renderer.c b/waltham-transmitter/waltham-renderer/waltham-renderer.c
new file mode 100644 (file)
index 0000000..d274e3b
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+#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 "compositor.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);
+               break;
+       }
+
+       case GST_MESSAGE_STATE_CHANGED:
+       {
+               GstState oldstate, newstate;
+
+               gst_message_parse_state_changed(message, &oldstate, &newstate, NULL);
+               switch (newstate){
+               case GST_STATE_NULL:
+                       fprintf(stderr, "%s: state is NULL\n", GST_MESSAGE_SRC_NAME(message));
+               }
+               break;
+       }
+        default:
+               fprintf(stderr, "Unhandled message\n");
+               break;
+       }
+}
+
+static int
+gst_pipe_init(struct weston_transmitter_output *output, struct gst_settings *settings)
+{
+       struct GstAppContext *gstctx;
+       gstctx=zalloc(sizeof (*gstctx));
+       if(!gstctx){
+               weston_log("Enable to allocate memory\n");
+               return -1;
+       }
+       GstCaps *caps;
+       int ret = 0;
+       GError *gerror = NULL;
+       FILE * pFile;
+       long lSize;
+       char * pipe = NULL;
+       size_t res;
+
+       /* create gstreamer pipeline */
+       gst_init(NULL, NULL);
+       gstctx->loop = g_main_loop_new(NULL, FALSE);
+
+       /* read pipeline from file */
+       pFile = fopen ( "/etc/xdg/weston/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 = (char*) 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");
+       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;
+
+       return 0;
+}
+
+static int
+recorder_enable(struct weston_transmitter_output *output)
+{
+       struct gst_settings *settings;
+
+       struct weston_output* base = &output->base;
+       struct weston_compositor *compositor = base->compositor;
+       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);
+
+       return 0;
+err:
+       weston_log("[gst recorder] %s:"
+               " invalid settings\n",
+               output->base.name);
+       free(settings);
+       return -1;
+}
+
+static void waltham_renderer_repaint_output(struct weston_transmitter_output *output)
+{
+       GstBuffer *gstbuffer;
+       GstMemory *mem;
+       GstAllocator *allocator;
+       int stride = output->renderer->surface_width * 4;
+       gsize offset = 0;
+
+       if(!output->renderer->recorder_enabled)
+       {
+               recorder_enable(&output->base);
+               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(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;
+
+       return 0;
+}
+
+WL_EXPORT struct waltham_renderer_interface waltham_renderer_interface = {
+               .display_create = waltham_renderer_display_create
+};
diff --git a/waltham-transmitter/waltham-renderer/waltham-renderer.h b/waltham-transmitter/waltham-renderer/waltham-renderer.h
new file mode 100644 (file)
index 0000000..a9ac513
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 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_ */