From: Wataru Mizuno Date: Wed, 11 Apr 2018 07:15:33 +0000 (+0900) Subject: meta-agl: introduce transmitter plugin to weston X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=commitdiff_plain;h=b6621bdb07daac4955300549dcadccf28069026a;p=AGL%2Fmeta-agl.git meta-agl: introduce transmitter plugin to weston The transmitter plugin is one of weston plugin which enables to share surface to remote site. v2 (jsmoeller): rebased to new layer structure Change-Id: I7dae9b1acf2d8acc8f736da9a36ae21d11a30203 Signed-off-by: Wataru Mizuno Signed-off-by: Jan-Simon Möller --- diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/waltham_git.bb b/meta-agl-profile-graphical/recipes-graphics/wayland/waltham_git.bb new file mode 100644 index 000000000..55123e9bf --- /dev/null +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/waltham_git.bb @@ -0,0 +1,16 @@ +DESCRIPTION = "Waltham is a network IPC library designed to resemble Wayland both protocol and protocol-API wise" +HOMEPAGE = "https://github.com/waltham/waltham" + +LICENSE = "MIT" +LIC_FILES_CHKSUM = " \ + file://LICENSE;md5=e8ad01a5182f2c1b3a2640e9ea268264 \ +" +SRCREV = "${AUTOREV}" +SRC_URI = "git://github.com/wmizuno/waltham.git \ + " +S = "${WORKDIR}/git" + +inherit autotools pkgconfig + +DEPENDS += "libdrm virtual/kernel wayland" +RDEPENDS_${PN} += "libdrm" \ No newline at end of file diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0017-transmitter-add-an-incomplete-plugin-output-and-poin.patch b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0017-transmitter-add-an-incomplete-plugin-output-and-poin.patch new file mode 100644 index 000000000..bf2f05ef1 --- /dev/null +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0017-transmitter-add-an-incomplete-plugin-output-and-poin.patch @@ -0,0 +1,2154 @@ +From aa3ea1af1dfa0e0ef5b452d8a5c53cd3eb508f52 Mon Sep 17 00:00:00 2001 +From: Pekka Paalanen +Date: Wed, 2 Mar 2016 16:57:45 +0200 +Subject: [PATCH 1/3] transmitter: add an incomplete plugin (output and + pointer) + +Enabled with ./configure --enable-surface-remoting + +Draft the public API for binding and unbinding a surface for remoting, +and another for ivi-shell specifics. + +Add the plumbing needed to relay a configure event from the network to +the shell, to be forwarded to the application. + +Implement support for (fake) connection object tracking. + +Create a weston_output for a (fake) remote output. Force the +sync-to-output on remoted surfaces. Use timers to fake wl_surface.enter +and frame callback events. Also Presentation feedback is poorly faked. + +Hooking to weston_surface happens in two ways: surface_configure in +Transmitter plugin API is used to relay the dx,dy from +wl_surface.attach, and weston_surface::apply_state_signal relays state +updates. + +Create a fake seat with pointer: + +- Add an internal pointer API that will be called by the networking code + for incoming input events. The API should match 1:1 to the events. + These functions will reimplement the parts of src/input.c to send out + the events to Wayland clients. + +- Implement pointer enter/leave of the internal pointer API. Code is + mimicked from weston_pointer_set_focus(), but without all the logic + needed to determine the right actions. + +- Implement pointer frame of the internal pointer API. + +- Add a fake pointer input generator. It only make the pointer enter the + surface remoted the most recently, and moves the pointer in a circle. + +All ways of getting pointer focus should be covered. Serial tracking is +the same as in Weston core. Seat maintains the pointer focus surface. +Focus_client is managed while Weston core never sees any focus. +Transmitter surface gained a destroy signal. + +Surface destruction relies on forwarding the destroy to the remote, +which will then reply with appropriate pointer.leave events. This is not +implemented by the input faking code. + +Transmitter is expected to open all inputs available on the remote and +multiplex those to local clients as clients subscribe. + +Notes about the design and guidelines for finishing the implementation +are included, and all the mockup code is annotated as "fake" so it is +easy to spot and replace with a proper network implementation. + +There are listener-based APIs for getting both remote connection status +changes, and per-surface stream status changes. + +Signed-off-by: Pekka Paalanen +--- + Makefile.am | 19 ++ + configure.ac | 9 + + transmitter/README | 53 ++++ + transmitter/input.c | 597 +++++++++++++++++++++++++++++++++++++++ + transmitter/output.c | 234 ++++++++++++++++ + transmitter/plugin.c | 638 ++++++++++++++++++++++++++++++++++++++++++ + transmitter/plugin.h | 207 ++++++++++++++ + transmitter/transmitter_api.h | 253 +++++++++++++++++ + 8 files changed, 2010 insertions(+) + create mode 100644 transmitter/README + create mode 100644 transmitter/input.c + create mode 100644 transmitter/output.c + create mode 100644 transmitter/plugin.c + create mode 100644 transmitter/plugin.h + create mode 100644 transmitter/transmitter_api.h + +diff --git a/Makefile.am b/Makefile.am +index cdf82ab..6cca875 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -502,6 +502,25 @@ cms_colord_la_SOURCES = \ + endif + endif + ++if ENABLE_SURFACE_REMOTING ++module_LTLIBRARIES += transmitter.la ++transmitter_la_LDFLAGS = -module -avoid-version ++transmitter_la_CFLAGS = \ ++ $(COMPOSITOR_CFLAGS) \ ++ $(AM_CFLAGS) ++transmitter_la_LIBADD = $(COMPOSITOR_LIBS) ++transmitter_la_SOURCES = \ ++ transmitter/plugin.c \ ++ transmitter/plugin.h \ ++ transmitter/output.c \ ++ transmitter/input.c \ ++ transmitter/transmitter_api.h \ ++ shared/helpers.h \ ++ shared/timespec-util.h \ ++ shared/zalloc.h \ ++ src/compositor.h ++endif ++ + noinst_PROGRAMS += spring-tool + spring_tool_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS) + spring_tool_LDADD = $(COMPOSITOR_LIBS) -lm +diff --git a/configure.ac b/configure.ac +index d0dee1b..06cda73 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -562,6 +562,14 @@ AS_IF([test "x$have_systemd_login_209" = "xyes"], + [AC_DEFINE([HAVE_SYSTEMD_LOGIN_209], [1], [Have systemd-login >= 209])]) + + ++# surface remoting ++AC_ARG_ENABLE(surface-remoting, ++ AS_HELP_STRING([--enable-surface-remoting], ++ [support for surface remoting over network]),, ++ enable_surface_remoting=no) ++AM_CONDITIONAL(ENABLE_SURFACE_REMOTING, test "x$enable_surface_remoting" = "xyes") ++ ++ + # Note that other features might want libxml2, or this feature might use + # alternative xml libraries at some point. Therefore the feature and + # pre-requisite concepts are split. +@@ -750,4 +758,5 @@ AC_MSG_RESULT([ + libunwind Support ${have_libunwind} + VA H.264 encoding Support ${have_libva} + GStreamer H.264 enc. Support ${enable_gst_recorder} ++ Surface remoting support ${enable_surface_remoting} + ]) +diff --git a/transmitter/README b/transmitter/README +new file mode 100644 +index 0000000..a7977ba +--- /dev/null ++++ b/transmitter/README +@@ -0,0 +1,53 @@ ++Testing Transmitter with ivi-shell ++ ++The current implementation of Transmitter is a stub which interfaces to ++other Weston parts appropriately, but all networking is just a mockup. ++ ++ ++Configure Weston with --enable-surface-remoting to build the Transmitter ++plugin. ++ ++In weston.ini, add 'transmitter.so' to the 'modules' key under '[core]', and ++make sure the 'shell' is 'ivi-shell.so'. Follow the ivi-shell example ++weston.ini for everything else. ++ ++When you start weston, the log should contain something like this: ++ ++[13:13:54.799] Loading module '/home/pq/local/lib/weston/ivi-shell.so' ++[13:13:54.799] launching '/home/pq/local/libexec/weston-keyboard' ++[13:13:54.799] Loading module '/home/pq/local/lib/weston/hmi-controller.so' ++[13:13:54.799] Loading module '/home/pq/local/lib/weston/transmitter.so' ++[13:13:54.799] Registered plugin API 'transmitter_v1' of size 48 ++[13:13:54.799] Registered plugin API 'transmitter_ivi_v1' of size 16 ++[13:13:54.799] Transmitter initialized. ++[13:13:54.799] ivi-layout: Transmitter enabled. ++[13:13:54.799] launching '/home/pq/build/weston/weston-ivi-shell-user-interface' ++[13:13:54.799] hmi-controller: Transmitter enabled. ++[13:13:54.799] Transmitter connecting to 0.0.0.0:66... ++[13:13:55.800] Transmitter connected to 0.0.0.0:66. ++[13:13:55.800] hmi-controller: connection status 0 ++[13:13:55.800] Transmitter created output 'transmitter-0.0.0.0:66-1': Weston-Transmitter, transmitter-0.0.0.0:66-1, 0 ++[13:13:55.800] Transmitter created seat=0x1c37bd0 'transmitter-0.0.0.0:66-default' ++[13:13:55.800] Transmitter created pointer=0x1c38430 for seat 0x1c37bd0 ++[13:13:55.800] transmitter_start_repaint_loop(transmitter-0.0.0.0:66-1) ++ ++ ++If you have edited a client to have ivi-id >= 0xfaa01000, when you start that ++client it should be "remoted" automatically and not appear on screen. ++ ++You can also manually start remoting: ++- Start an IVI application. ++- Move pointer onto the application window. ++- Press Mod+Shift+space, and then 'k'. ++- The window should disappear. ++ ++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 ++ ++Once remoting has started, the mockup code will generate fake pointer input for ++the window. This can be seen with e.g. weston-eventdemo, or running an ++application with WAYLAND_DEBUG=client. +diff --git a/transmitter/input.c b/transmitter/input.c +new file mode 100644 +index 0000000..0ba04d4 +--- /dev/null ++++ b/transmitter/input.c +@@ -0,0 +1,597 @@ ++/* ++ * Copyright (C) 2016 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 "config.h" ++ ++#include ++#include ++#include ++ ++/* for fake stuff */ ++#include ++ ++#include "compositor.h" ++#include "helpers.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, ++}; ++ ++/* 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); ++ ++ seat->get_pointer_listener.notify = seat_get_pointer_handler; ++ wl_signal_add(&seat->base.get_pointer_signal, ++ &seat->get_pointer_listener); ++ ++ 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_client = weston_pointer_get_pointer_client(pointer, ++ client); ++ 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) ++{ ++ assert(!"TODO"); ++} ++ ++void ++transmitter_seat_pointer_axis(struct weston_transmitter_seat *seat, ++ uint32_t time, ++ uint32_t axis, ++ wl_fixed_t value) ++{ ++ assert(!"TODO"); ++} ++ ++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) ++{ ++ assert(!"TODO"); ++} ++ ++void ++transmitter_seat_pointer_axis_stop(struct weston_transmitter_seat *seat, ++ uint32_t time, ++ uint32_t axis) ++{ ++ assert(!"TODO"); ++} ++ ++void ++transmitter_seat_pointer_axis_discrete(struct weston_transmitter_seat *seat, ++ uint32_t axis, ++ int32_t discrete) ++{ ++ assert(!"TODO"); ++} ++ ++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); ++ ++ weston_seat_release(&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); ++} ++ ++int ++transmitter_remote_create_seat(struct weston_transmitter_remote *remote) ++{ ++ struct weston_transmitter_seat *seat = NULL; ++ char *name = 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; ++ ++ 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); ++ ++ /* XXX: mirror remote capabilities */ ++ transmitter_seat_create_pointer(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/transmitter/output.c b/transmitter/output.c +new file mode 100644 +index 0000000..6a78721 +--- /dev/null ++++ b/transmitter/output.c +@@ -0,0 +1,234 @@ ++/* ++ * Copyright (C) 2016 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 "config.h" ++ ++#include ++#include ++#include ++ ++#include "compositor.h" ++#include "helpers.h" ++ ++#include "plugin.h" ++#include "transmitter_api.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 inline struct weston_transmitter_output * ++to_transmitter_output(struct weston_output *base) ++{ ++ return container_of(base, struct weston_transmitter_output, base); ++} ++ ++static char * ++make_model(struct weston_transmitter_remote *remote, int name) ++{ ++ char *str; ++ ++ if (asprintf(&str, "transmitter-%s-%d", remote->addr, 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 = container_of(mode_list->next, struct weston_mode, link); ++ ++ wl_list_remove(&mode->link); ++ free(mode); ++ } ++} ++ ++void ++transmitter_output_destroy(struct weston_transmitter_output *output) ++{ ++ weston_log("Transmitter destroying output '%s'\n", output->base.name); ++ ++ 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 = to_transmitter_output(base); ++ ++ transmitter_output_destroy(output); ++} ++ ++static void ++transmitter_start_repaint_loop(struct weston_output *base) ++{ ++ weston_log("%s(%s)\n", __func__, base->name); ++} ++ ++static int ++transmitter_output_repaint(struct weston_output *base, ++ pixman_region32_t *damage) ++{ ++ weston_log("%s(%s)\n", __func__, base->name); ++ ++ return -1; ++} ++ ++int ++transmitter_remote_create_output( ++ struct weston_transmitter_remote *remote, ++ const struct weston_transmitter_output_info *info) ++{ ++ struct weston_transmitter_output *output; ++ ++ output = zalloc(sizeof *output); ++ if (!output) ++ return -1; ++ ++ 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"); ++ ++ 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); ++ /* 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.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->remote = remote; ++ wl_list_insert(&remote->output_list, &output->link); ++ ++ weston_log("Transmitter created output '%s': %s, %s, %s\n", ++ output->base.name, output->base.make, output->base.model, ++ output->base.serial_number); ++ ++ 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/transmitter/plugin.c b/transmitter/plugin.c +new file mode 100644 +index 0000000..c5e56d3 +--- /dev/null ++++ b/transmitter/plugin.c +@@ -0,0 +1,638 @@ ++/* ++ * Copyright (C) 2016 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 "config.h" ++ ++#include ++#include ++#include ++#include ++ ++#include "compositor.h" ++#include "helpers.h" ++#include "timespec-util.h" ++ ++#include "plugin.h" ++#include "transmitter_api.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. ++ */ ++ ++/** 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 int ++frame_callback_handler(void *data) /* fake */ ++{ ++ struct weston_transmitter_surface *txs = data; ++ struct weston_frame_callback *cb, *cnext; ++ struct weston_output *output; ++ struct weston_compositor *compositor; ++ uint32_t frame_time; ++ uint32_t presented_flags; ++ int32_t refresh_nsec; ++ struct timespec stamp; ++ ++ compositor = txs->remote->transmitter->compositor; ++ output = txs->sync_output; ++ ++ /* wl_surface.enter should arrive before any frame callbacks, ++ * but remote might send frame callbacks for non-visible too. ++ */ ++ if (!output) ++ return 0; ++ ++ /* XXX: eeeew */ ++ frame_time = weston_compositor_get_time(); ++ ++ wl_list_for_each_safe(cb, cnext, &txs->frame_callback_list, link) { ++ wl_callback_send_done(cb->resource, frame_time); ++ wl_resource_destroy(cb->resource); ++ } ++ ++ presented_flags = 0; ++ refresh_nsec = millihz_to_nsec(output->current_mode->refresh); ++ /* XXX: waaahhhahaa */ ++ weston_compositor_read_presentation_clock(compositor, &stamp); ++ weston_presentation_feedback_present_list(&txs->feedback_list, ++ output, refresh_nsec, &stamp, ++ output->msc, ++ presented_flags); ++ ++ return 0; ++} ++ ++static void ++fake_frame_callback(struct weston_transmitter_surface *txs) ++{ ++ struct weston_transmitter *txr = txs->remote->transmitter; ++ struct wl_event_loop *loop; ++ ++ if (!txs->frame_timer) { ++ loop = wl_display_get_event_loop(txr->compositor->wl_display); ++ txs->frame_timer = ++ wl_event_loop_add_timer(loop, ++ frame_callback_handler, txs); ++ } ++ ++ wl_event_source_timer_update(txs->frame_timer, 85); ++} ++ ++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 ++transmitter_surface_gather_state(struct weston_transmitter_surface *txs) ++{ ++ weston_log("Transmitter: update surface %p (%d, %d), %d cb\n", ++ txs->surface, txs->attach_dx, txs->attach_dy, ++ wl_list_length(&txs->surface->frame_callback_list)); ++ ++ wl_list_insert_list(&txs->frame_callback_list, ++ &txs->surface->frame_callback_list); ++ wl_list_init(&txs->surface->frame_callback_list); ++ ++ wl_list_insert_list(&txs->feedback_list, &txs->surface->feedback_list); ++ wl_list_init(&txs->surface->feedback_list); ++ ++ /* TODO: transmit surface state to remote */ ++ ++ txs->attach_dx = 0; ++ txs->attach_dy = 0; ++} ++ ++/** weston_surface apply state signal handler */ ++static void ++transmitter_surface_apply_state(struct wl_listener *listener, void *data) ++{ ++ struct weston_transmitter_surface *txs = ++ container_of(listener, struct weston_transmitter_surface, ++ apply_state_listener); ++ ++ assert(data == NULL); ++ ++ transmitter_surface_gather_state(txs); ++ fake_frame_callback(txs); ++} ++ ++/** 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_frame_callback *framecb, *cnext; ++ ++ /* may be called multiple times */ ++ if (!txs->surface) ++ return; ++ ++ wl_signal_emit(&txs->destroy_signal, txs); ++ ++ wl_list_remove(&txs->surface_destroy_listener.link); ++ weston_log("Transmitter unbound surface %p.\n", txs->surface); ++ txs->surface = NULL; ++ ++ wl_list_remove(&txs->sync_output_destroy_listener.link); ++ wl_list_remove(&txs->apply_state_listener.link); ++ ++ if (txs->map_timer) ++ wl_event_source_remove(txs->map_timer); ++ if (txs->frame_timer) ++ wl_event_source_remove(txs->frame_timer); ++ ++ weston_presentation_feedback_discard_list(&txs->feedback_list); ++ wl_list_for_each_safe(framecb, cnext, &txs->frame_callback_list, link) ++ wl_resource_destroy(framecb->resource); ++ ++ /* 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 = ++ container_of(listener, struct weston_transmitter_surface, ++ surface_destroy_listener); ++ ++ assert(data == txs->surface); ++ ++ transmitter_surface_zombify(txs); ++} ++ ++static struct weston_transmitter_surface * ++transmitter_surface_get(struct weston_surface *ws) ++{ ++ struct wl_listener *listener; ++ struct weston_transmitter_surface *txs; ++ ++ listener = wl_signal_get(&ws->destroy_signal, ++ transmitter_surface_destroyed); ++ ++ if (!listener) ++ return NULL; ++ ++ txs = container_of(listener, struct weston_transmitter_surface, ++ surface_destroy_listener); ++ assert(ws == txs->surface); ++ ++ return txs; ++} ++ ++static void ++sync_output_destroy_handler(struct wl_listener *listener, void *data) ++{ ++ struct weston_transmitter_surface *txs; ++ ++ txs = container_of(listener, struct weston_transmitter_surface, ++ 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 ++fake_input(struct weston_transmitter_surface *txs) ++{ ++ struct wl_list *seat_list = &txs->remote->seat_list; ++ struct weston_transmitter_seat *seat; ++ ++ assert(wl_list_length(seat_list) == 1); ++ seat = container_of(seat_list->next, ++ struct weston_transmitter_seat, link); ++ ++ transmitter_seat_fake_pointer_input(seat, txs); ++} ++ ++/* fake receiving wl_surface.enter(output) */ ++static int ++map_timer_handler(void *data) ++{ ++ struct weston_transmitter_surface *txs = data; ++ struct weston_transmitter_output *output; ++ ++ assert(!wl_list_empty(&txs->remote->output_list)); ++ ++ output = container_of(txs->remote->output_list.next, ++ struct weston_transmitter_output, link); ++ ++ txs->sync_output = &output->base; ++ txs->sync_output_destroy_listener.notify = sync_output_destroy_handler; ++ wl_list_remove(&txs->sync_output_destroy_listener.link); ++ wl_signal_add(&txs->sync_output->destroy_signal, ++ &txs->sync_output_destroy_listener); ++ ++ weston_surface_force_output(txs->surface, txs->sync_output); ++ ++ weston_log("Transmitter: surface %p entered output %s\n", ++ txs->surface, txs->sync_output->name); ++ ++ fake_frame_callback(txs); ++ fake_input(txs); ++ ++ return 0; ++} ++ ++/* Fake a delay for the remote end to map the surface to an output */ ++static void ++fake_output_mapping(struct weston_transmitter_surface *txs) ++{ ++ struct weston_transmitter *txr = txs->remote->transmitter; ++ struct wl_event_loop *loop; ++ ++ loop = wl_display_get_event_loop(txr->compositor->wl_display); ++ txs->map_timer = wl_event_loop_add_timer(loop, map_timer_handler, txs); ++ wl_event_source_timer_update(txs->map_timer, 400); ++} ++ ++/* Fake getting "connection established" from the content streamer. */ ++static void ++fake_stream_opening_handler(void *data) ++{ ++ struct weston_transmitter_surface *txs = data; ++ ++ /* ...once the connection is up: */ ++ txs->status = WESTON_TRANSMITTER_STREAM_LIVE; ++ wl_signal_emit(&txs->stream_status_signal, txs); ++ ++ /* need to create the surface on the remote and set all state */ ++ transmitter_surface_gather_state(txs); ++ ++ fake_output_mapping(txs); ++} ++ ++/* Fake a callback from content streamer. */ ++static void ++fake_stream_opening(struct weston_transmitter_surface *txs) ++{ ++ struct weston_transmitter *txr = txs->remote->transmitter; ++ struct wl_event_loop *loop; ++ ++ loop = wl_display_get_event_loop(txr->compositor->wl_display); ++ wl_event_loop_add_idle(loop, fake_stream_opening_handler, txs); ++} ++ ++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_surface *txs; ++ ++ if (transmitter_surface_get(ws)) { ++ weston_log("Transmitter: surface %p already bound.\n", ws); ++ return 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); ++ 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); ++ ++ txs->apply_state_listener.notify = transmitter_surface_apply_state; ++ wl_signal_add(&ws->apply_state_signal, &txs->apply_state_listener); ++ ++ wl_list_init(&txs->sync_output_destroy_listener.link); ++ ++ wl_list_init(&txs->frame_callback_list); ++ wl_list_init(&txs->feedback_list); ++ ++ /* TODO: create the content stream connection... */ ++ fake_stream_opening(txs); ++ ++ return txs; ++} ++ ++static enum weston_transmitter_stream_status ++transmitter_surface_get_stream_status(struct weston_transmitter_surface *txs) ++{ ++ return txs->status; ++} ++ ++static int ++conn_timer_handler(void *data) /* fake */ ++{ ++ struct weston_transmitter_remote *remote = data; ++ struct weston_transmitter_output_info info = { ++ WL_OUTPUT_SUBPIXEL_NONE, ++ WL_OUTPUT_TRANSFORM_NORMAL, ++ 1, ++ 0, 0, ++ 300, 200, ++ "fake", ++ { ++ WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, ++ 800, 600, ++ 51519, ++ { NULL, NULL } ++ } ++ }; ++ ++ weston_log("Transmitter connected to %s.\n", remote->addr); ++ remote->status = WESTON_TRANSMITTER_CONNECTION_READY; ++ wl_signal_emit(&remote->connection_status_signal, remote); ++ ++ wl_event_source_remove(remote->conn_timer); ++ remote->conn_timer = NULL; ++ ++ /* 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); ++ ++ return 0; ++} ++ ++static struct weston_transmitter_remote * ++transmitter_connect_to_remote(struct weston_transmitter *txr, ++ const char *addr, ++ struct wl_listener *status) ++{ ++ struct weston_transmitter_remote *remote; ++ struct wl_event_loop *loop; ++ ++ remote = zalloc(sizeof (*remote)); ++ if (!remote) ++ return NULL; ++ ++ remote->transmitter = txr; ++ wl_list_insert(&txr->remote_list, &remote->link); ++ remote->addr = strdup(addr); ++ remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; ++ wl_signal_init(&remote->connection_status_signal); ++ wl_signal_add(&remote->connection_status_signal, status); ++ wl_list_init(&remote->output_list); ++ wl_list_init(&remote->surface_list); ++ wl_list_init(&remote->seat_list); ++ ++ /* XXX: actually start connecting */ ++ weston_log("Transmitter connecting to %s...\n", addr); ++ /* fake it with a one second timer */ ++ loop = wl_display_get_event_loop(txr->compositor->wl_display); ++ remote->conn_timer = wl_event_loop_add_timer(loop, conn_timer_handler, ++ remote); ++ wl_event_source_timer_update(remote->conn_timer, 1000); ++ ++ 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. ++ */ ++ weston_log("Transmitter disconnecting from %s.\n", remote->addr); ++ ++ if (remote->conn_timer) ++ wl_event_source_remove(remote->conn_timer); ++ ++ 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); ++ ++ 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 = ++ container_of(listener, struct weston_transmitter, ++ 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); ++ ++ weston_log("Transmitter terminating.\n"); ++ 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 = container_of(listener, struct weston_transmitter, ++ compositor_destroy_listener); ++ assert(compositor == txr->compositor); ++ ++ return txr; ++} ++ ++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, ++}; ++ ++static void ++transmitter_surface_set_ivi_id(struct weston_transmitter_surface *txs, ++ uint32_t ivi_id) ++{ ++ assert(txs->surface); ++ if (!txs->surface) ++ return; ++ ++ weston_log("%s(%p, %#x)\n", __func__, txs->surface, ivi_id); ++} ++ ++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_ivi_id, ++ transmitter_surface_set_resize_callback, ++}; ++ ++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) ++ 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"); ++ ++ return 0; ++ ++fail: ++ wl_list_remove(&txr->compositor_destroy_listener.link); ++ free(txr); ++ ++ return -1; ++} +diff --git a/transmitter/plugin.h b/transmitter/plugin.h +new file mode 100644 +index 0000000..710b543 +--- /dev/null ++++ b/transmitter/plugin.h +@@ -0,0 +1,207 @@ ++/* ++ * Copyright (C) 2016 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 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 ++ ++#include "compositor.h" ++#include "transmitter_api.h" ++ ++struct weston_transmitter { ++ struct weston_compositor *compositor; ++ struct wl_listener compositor_destroy_listener; ++ ++ struct wl_list remote_list; /* transmitter_remote::link */ ++}; ++ ++struct weston_transmitter_remote { ++ struct weston_transmitter *transmitter; ++ struct wl_list link; ++ ++ char *addr; ++ ++ enum weston_transmitter_connection_status status; ++ struct wl_signal connection_status_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_event_source *conn_timer; /* fake */ ++}; ++ ++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; ++ struct wl_listener apply_state_listener; ++ ++ weston_transmitter_ivi_resize_handler_t resize_handler; ++ void *resize_handler_data; ++ ++ struct weston_output *sync_output; ++ struct wl_listener sync_output_destroy_listener; ++ ++ struct wl_event_source *map_timer; /* fake */ ++ struct wl_event_source *frame_timer; /* fake */ ++ ++ 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 */ ++}; ++ ++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 weston_transmitter_remote *remote; ++ struct wl_list link; /* weston_transmitter_remote::output_list */ ++}; ++ ++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 */ ++ ++ /* touch */ ++}; ++ ++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); ++ ++ ++#endif /* WESTON_TRANSMITTER_PLUGIN_H */ +diff --git a/transmitter/transmitter_api.h b/transmitter/transmitter_api.h +new file mode 100644 +index 0000000..95d82ec +--- /dev/null ++++ b/transmitter/transmitter_api.h +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (C) 2016 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 WESTON_TRANSMITTER_API_H ++#define WESTON_TRANSMITTER_API_H ++ ++#include "plugin-registry.h" ++ ++#include ++ ++/** \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 addr Address of the remote server. ++ * \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. ++ * ++ * The address argument is a string in the form "host:port". ++ */ ++ struct weston_transmitter_remote * ++ (*connect_to_remote)(struct weston_transmitter *txr, ++ const char *addr, ++ struct wl_listener *status); ++ ++ /** ++ * 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); ++}; ++ ++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 */ ++ ++#endif /* WESTON_TRANSMITTER_API_H */ +-- +2.7.4 + diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0018-ivi-layout-Register-ivi-layout-interface-It-enables-.patch b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0018-ivi-layout-Register-ivi-layout-interface-It-enables-.patch new file mode 100644 index 000000000..b8f935712 --- /dev/null +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0018-ivi-layout-Register-ivi-layout-interface-It-enables-.patch @@ -0,0 +1,49 @@ +From 8e586a78c7e74f0faaddd02abbdfcf6879d0f096 Mon Sep 17 00:00:00 2001 +From: Wataru Mizuno +Date: Wed, 27 Sep 2017 09:09:17 +0900 +Subject: [PATCH 2/3] ivi-layout :Register ivi-layout-interface It enables to + use ivi-layout-interface without load module + +Signed-off-by: Wataru Mizuno +--- + ivi-shell/ivi-layout-export.h | 2 ++ + ivi-shell/ivi-layout.c | 4 ++++ + 2 files changed, 6 insertions(+) + +diff --git a/ivi-shell/ivi-layout-export.h b/ivi-shell/ivi-layout-export.h +index 2317d6e..11ea874 100644 +--- a/ivi-shell/ivi-layout-export.h ++++ b/ivi-shell/ivi-layout-export.h +@@ -63,6 +63,8 @@ extern "C" { + #define IVI_SUCCEEDED (0) + #define IVI_FAILED (-1) + ++#define IVI_LAYOUT_API_NAME "ivi_layout_api_v1" ++ + struct ivi_layout_layer; + struct ivi_layout_screen; + struct ivi_layout_surface; +diff --git a/ivi-shell/ivi-layout.c b/ivi-shell/ivi-layout.c +index 64e4ead..602a42f 100644 +--- a/ivi-shell/ivi-layout.c ++++ b/ivi-shell/ivi-layout.c +@@ -67,6 +67,7 @@ + #include "ivi-layout-export.h" + #include "ivi-layout-private.h" + #include "ivi-layout-shell.h" ++#include "plugin-registry.h" + + #include "shared/helpers.h" + #include "shared/os-compatibility.h" +@@ -2139,5 +2140,8 @@ load_controller_modules(struct weston_compositor *compositor, const char *module + p++; + } + ++ weston_plugin_api_register(compositor, IVI_LAYOUT_API_NAME, ++ &ivi_layout_interface, sizeof(struct ivi_layout_interface)); ++ + return 0; + } +-- +2.7.4 + diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0019-transmitter-transmitter-plugin-for-waltham-protocol.patch b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0019-transmitter-transmitter-plugin-for-waltham-protocol.patch new file mode 100644 index 000000000..6b4f276fe --- /dev/null +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0019-transmitter-transmitter-plugin-for-waltham-protocol.patch @@ -0,0 +1,2732 @@ +From 0d114839f299b6a9e3f504e75c22d636222c3b20 Mon Sep 17 00:00:00 2001 +From: Wataru Mizuno +Date: Tue, 10 Apr 2018 15:23:02 +0900 +Subject: [PATCH 3/3] transmitter: transmitter plugin for waltham protocol + +The transmitter plugin enables weston to communicate with +remote site compositor over the ethernet. +Communication is done with waltham protocol which is the +wayland like IPC protocol. + +Signed-off-by: Wataru Mizuno +--- + Makefile.am | 11 +- + configure.ac | 12 + + transmitter/README | 108 +++-- + transmitter/input.c | 783 ++++++++++++++++++++++++++++++++- + transmitter/output.c | 139 +++++- + transmitter/plugin.c | 875 ++++++++++++++++++++++++++----------- + transmitter/plugin.h | 140 +++++- + transmitter/transmitter_api.h | 26 +- + transmitter/weston.ini.transmitter | 21 + + 9 files changed, 1763 insertions(+), 352 deletions(-) + create mode 100644 transmitter/weston.ini.transmitter + +diff --git a/Makefile.am b/Makefile.am +index 6cca875..2cb1920 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -306,6 +306,11 @@ westoninclude_HEADERS += \ + ivi-shell/ivi-layout-export.h + endif + ++if ENABLE_SURFACE_REMOTING ++westoninclude_HEADERS += \ ++ transmitter/transmitter_api.h ++endif ++ + if ENABLE_EGL + libweston_module_LTLIBRARIES += gl-renderer.la + gl_renderer_la_LDFLAGS = -module -avoid-version +@@ -507,8 +512,10 @@ module_LTLIBRARIES += transmitter.la + transmitter_la_LDFLAGS = -module -avoid-version + transmitter_la_CFLAGS = \ + $(COMPOSITOR_CFLAGS) \ +- $(AM_CFLAGS) +-transmitter_la_LIBADD = $(COMPOSITOR_LIBS) ++ $(AM_CFLAGS) \ ++ $(WALTHAM_CFLAGS) ++transmitter_la_LIBADD = $(COMPOSITOR_LIBS) \ ++ -lwaltham + transmitter_la_SOURCES = \ + transmitter/plugin.c \ + transmitter/plugin.h \ +diff --git a/configure.ac b/configure.ac +index 6cf2883..4819e08 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -543,6 +543,18 @@ AC_ARG_ENABLE(surface-remoting, + AS_HELP_STRING([--enable-surface-remoting], + [support for surface remoting over network]),, + enable_surface_remoting=no) ++if test "x$enable_surface_remoting" != "xno"; then ++ PKG_CHECK_MODULES(WALTHAM, ++ waltham >= 0.1.0, ++ have_waltham=yes, ++ have_waltham=no) ++ if test "x$have_waltham" = "xno" -a "x$enable_surface_remoting" = "xyes"; then ++ AC_MSG_ERROR([surface_remoting support explicitly requested, but waltham couldn't be found]) ++ fi ++ if test "x$have_waltham" = "xyes"; then ++ enable_surface_remoting=yes ++ fi ++fi + AM_CONDITIONAL(ENABLE_SURFACE_REMOTING, test "x$enable_surface_remoting" = "xyes") + + +diff --git a/transmitter/README b/transmitter/README +index a7977ba..af80574 100644 +--- a/transmitter/README ++++ b/transmitter/README +@@ -1,45 +1,84 @@ +-Testing Transmitter with ivi-shell ++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. + +-In weston.ini, add 'transmitter.so' to the 'modules' key under '[core]', and +-make sure the 'shell' is 'ivi-shell.so'. Follow the ivi-shell example +-weston.ini for everything else. +- +-When you start weston, the log should contain something like this: +- +-[13:13:54.799] Loading module '/home/pq/local/lib/weston/ivi-shell.so' +-[13:13:54.799] launching '/home/pq/local/libexec/weston-keyboard' +-[13:13:54.799] Loading module '/home/pq/local/lib/weston/hmi-controller.so' +-[13:13:54.799] Loading module '/home/pq/local/lib/weston/transmitter.so' +-[13:13:54.799] Registered plugin API 'transmitter_v1' of size 48 +-[13:13:54.799] Registered plugin API 'transmitter_ivi_v1' of size 16 +-[13:13:54.799] Transmitter initialized. +-[13:13:54.799] ivi-layout: Transmitter enabled. +-[13:13:54.799] launching '/home/pq/build/weston/weston-ivi-shell-user-interface' +-[13:13:54.799] hmi-controller: Transmitter enabled. +-[13:13:54.799] Transmitter connecting to 0.0.0.0:66... +-[13:13:55.800] Transmitter connected to 0.0.0.0:66. +-[13:13:55.800] hmi-controller: connection status 0 +-[13:13:55.800] Transmitter created output 'transmitter-0.0.0.0:66-1': Weston-Transmitter, transmitter-0.0.0.0:66-1, 0 +-[13:13:55.800] Transmitter created seat=0x1c37bd0 'transmitter-0.0.0.0:66-default' +-[13:13:55.800] Transmitter created pointer=0x1c38430 for seat 0x1c37bd0 +-[13:13:55.800] transmitter_start_repaint_loop(transmitter-0.0.0.0:66-1) +- +- +-If you have edited a client to have ivi-id >= 0xfaa01000, when you start that +-client it should be "remoted" automatically and not appear on screen. +- +-You can also manually start remoting: ++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 repository. ++ ++If you set 'WALTHAM_DEBUG=1' to your environment valuable, you can ++see the log like this: ++ ++ [06:12:41.238] Loading module '/usr/lib64/weston/ivi-shell.so' ++ [06:12:41.245] launching '/usr/libexec/weston-keyboard' ++ [06:12:41.247] Loading module '/usr/lib64/weston/ivi-controller.so' ++ [06:12:41.252] Loading module '/usr/lib64/weston/ivi-input-controller.so' ++ [06:12:41.253] ivi-input-controller module loaded successfully! ++ [06:12:41.255] Loading module '/usr/lib64/weston/transmitter.so' ++ [06:12:41.260] Registered plugin API 'transmitter_v1' of size 88 ++ [06:12:41.260] Registered plugin API 'transmitter_ivi_v1' of size 16 ++ [06:12:41.260] Transmitter initialized. ++ [06:12:41.260] ivi-layout: Transmitter enabled. ++ [06:12:41.260] Transmitter weston_seat 0x14f8010 ++ [06:12:41.260] Transmitter created pointer=0x139a440 for seat 0x14f8010 ++ [06:12:41.261] Transmitter created keyboard=0x14f8160 for seat 0x14f8010 ++ [06:12:41.261] Transmitter created touch=0x1508750 for seat 0x14f8010 ++ ++The connection is established, you can see following debug messages: ++ ++ root@gr-mrb-64:~# debug: wth_connection_insert_new_object: new object id: 1 ++ debug: wth_connection_insert_new_object: new object id: 2 ++ 2017-07-19T06:14:31Z 00001000030000000100000002000000 wth_display_get_registry ++ debug: wth_connection_insert_new_object: new object id: 3 ++ 2017-07-19T06:14:31Z 00001000020000000100000003000000 wth_display_sync ++ debug: Message received on conn 0x1560340: (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 ++ 2017-07-19T06:14:31Z 00002c000800000002000000010000000400000010000000777468705f636f6d706f7369746f720001000000 wthp_registry_bind ++ debug: Message received on conn 0x1560340: (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: 5 ++ 2017-07-19T06:14:31Z 000030000800000002000000010000000500000012000000777468705f626c6f625f666163746f72790001000000 wthp_registry_bind ++ debug: Message received on conn 0x1560340: (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: 6 ++ 2017-07-19T06:14:31Z 000034000800000002000000010000000600000015000000777468705f6976695f6170706c69636174696f6e0001000000 wthp_registry_bind ++ debug: Message received on conn 0x1560340: (11) 16 bytes ++ debug: wthp_callback_send_done(3, 0) (opcode 11) called. ++ sending wth_display.sync... ++ debug: wth_connection_insert_new_object: new object id: 7 ++ 2017-07-19T06:14:31Z 00001000020000000100000007000000 wth_display_sync ++ debug: Message received on conn 0x1560340: (11) 16 bytes ++ debug: wthp_callback_send_done(7, 0) (opcode 11) called. ++ ...sync done. ++ ++Start remoting : + - Start an IVI application. +-- Move pointer onto the application window. +-- Press Mod+Shift+space, and then 'k'. +-- The window should disappear. ++- Put surface on backend output ++- Put surface on transmitter output + + Weston log will indicate remoting has started: + +@@ -48,6 +87,3 @@ Weston log will indicate remoting has started: + [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 + +-Once remoting has started, the mockup code will generate fake pointer input for +-the window. This can be seen with e.g. weston-eventdemo, or running an +-application with WAYLAND_DEBUG=client. +diff --git a/transmitter/input.c b/transmitter/input.c +index 0ba04d4..eeb7452 100644 +--- a/transmitter/input.c ++++ b/transmitter/input.c +@@ -1,5 +1,6 @@ + /* + * Copyright (C) 2016 DENSO CORPORATION ++ * 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 +@@ -129,6 +130,79 @@ static const struct weston_pointer_grab_interface pointer_grab_impl = { + 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 +@@ -207,7 +281,7 @@ seat_get_pointer_handler(struct wl_listener *listener, void *data) + if (wl_resource_get_client(surface) != client) + return; + +- pointer = weston_seat_get_pointer(&seat->base); ++ pointer = weston_seat_get_pointer(seat->base); + assert(pointer); /* guaranteed by having pointer_focus */ + pointer_client = weston_pointer_get_pointer_client(pointer, client); + +@@ -235,13 +309,9 @@ transmitter_seat_create_pointer(struct weston_transmitter_seat *seat) + seat->pointer_focus = NULL; + wl_list_init(&seat->pointer_focus_destroy_listener.link); + +- weston_seat_init_pointer(&seat->base); +- +- seat->get_pointer_listener.notify = seat_get_pointer_handler; +- wl_signal_add(&seat->base.get_pointer_signal, +- &seat->get_pointer_listener); ++ weston_seat_init_pointer(seat->base); + +- pointer = weston_seat_get_pointer(&seat->base); ++ pointer = weston_seat_get_pointer(seat->base); + + /* not exported: + * weston_pointer_set_default_grab(pointer, &pointer_grab_impl); */ +@@ -252,7 +322,7 @@ transmitter_seat_create_pointer(struct weston_transmitter_seat *seat) + wl_list_init(&pointer->output_destroy_listener.link); + + weston_log("Transmitter created pointer=%p for seat %p\n", +- pointer, &seat->base); ++ pointer, seat->base); + } + + static void +@@ -279,7 +349,7 @@ transmitter_seat_pointer_enter(struct weston_transmitter_seat *seat, + struct wl_list *focus_resource_list; + struct wl_resource *resource; + +- pointer = weston_seat_get_pointer(&seat->base); ++ pointer = weston_seat_get_pointer(seat->base); + assert(pointer); + + assert(txs->surface); +@@ -299,8 +369,6 @@ transmitter_seat_pointer_enter(struct weston_transmitter_seat *seat, + seat->pointer_surface_x = surface_x; + seat->pointer_surface_y = surface_y; + +- pointer->focus_client = weston_pointer_get_pointer_client(pointer, +- client); + pointer->focus_serial = serial; + + /* pointer->focus is not used, because it is a weston_view, while +@@ -347,7 +415,7 @@ transmitter_seat_pointer_leave(struct weston_transmitter_seat *seat, + assert(txs->surface); + surface_resource = txs->surface->resource; + +- pointer = weston_seat_get_pointer(&seat->base); ++ pointer = weston_seat_get_pointer(seat->base); + assert(pointer); + if (!pointer->focus_client) + return; +@@ -373,7 +441,7 @@ transmitter_seat_pointer_motion(struct weston_transmitter_seat *seat, + struct wl_resource *resource; + struct weston_transmitter_surface *txs; + +- pointer = weston_seat_get_pointer(&seat->base); ++ pointer = weston_seat_get_pointer(seat->base); + assert(pointer); + + seat->pointer_surface_x = surface_x; +@@ -401,7 +469,27 @@ transmitter_seat_pointer_button(struct weston_transmitter_seat *seat, + uint32_t button, + uint32_t state) + { +- assert(!"TODO"); ++ 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 +@@ -410,7 +498,27 @@ transmitter_seat_pointer_axis(struct weston_transmitter_seat *seat, + uint32_t axis, + wl_fixed_t value) + { +- assert(!"TODO"); ++ 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 +@@ -418,7 +526,7 @@ transmitter_seat_pointer_frame(struct weston_transmitter_seat *seat) + { + struct weston_pointer *pointer; + +- pointer = weston_seat_get_pointer(&seat->base); ++ pointer = weston_seat_get_pointer(seat->base); + if (pointer) + weston_pointer_send_frame(pointer); + } +@@ -427,7 +535,7 @@ void + transmitter_seat_pointer_axis_source(struct weston_transmitter_seat *seat, + uint32_t axis_source) + { +- assert(!"TODO"); ++ /* ToDo : implement axis event handling */ + } + + void +@@ -435,7 +543,7 @@ transmitter_seat_pointer_axis_stop(struct weston_transmitter_seat *seat, + uint32_t time, + uint32_t axis) + { +- assert(!"TODO"); ++ /* ToDo : implement axis event handling */ + } + + void +@@ -443,7 +551,222 @@ transmitter_seat_pointer_axis_discrete(struct weston_transmitter_seat *seat, + uint32_t axis, + int32_t discrete) + { +- assert(!"TODO"); ++ /* 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 * +@@ -462,9 +785,7 @@ transmitter_seat_destroy(struct weston_transmitter_seat *seat) + { + wl_list_remove(&seat->link); + +- weston_log("Transmitter destroy seat=%p\n", &seat->base); +- +- weston_seat_release(&seat->base); ++ 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); +@@ -475,11 +796,406 @@ transmitter_seat_destroy(struct weston_transmitter_seat *seat) + 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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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 = container_of(seat_list->next, ++ struct weston_transmitter_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) +@@ -493,6 +1209,24 @@ transmitter_remote_create_seat(struct weston_transmitter_remote *remote) + 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); + +@@ -515,9 +1249,12 @@ transmitter_remote_create_seat(struct weston_transmitter_remote *remote) + + 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); + +@@ -582,7 +1319,7 @@ transmitter_seat_fake_pointer_input(struct weston_transmitter_seat *seat, + + if (!seat->pointer_timer) { + /* schedule timer for motion */ +- loop = wl_display_get_event_loop(seat->base.compositor->wl_display); ++ 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); +diff --git a/transmitter/output.c b/transmitter/output.c +index 6a78721..a3f8ed1 100644 +--- a/transmitter/output.c ++++ b/transmitter/output.c +@@ -1,5 +1,6 @@ + /* + * Copyright (C) 2016 DENSO CORPORATION ++ * 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 +@@ -73,7 +74,7 @@ make_model(struct weston_transmitter_remote *remote, int name) + { + char *str; + +- if (asprintf(&str, "transmitter-%s-%d", remote->addr, name) < 0) ++ if (asprintf(&str, "transmitter-%s:%s-%d", remote->addr, remote->port, name) < 0) + return NULL; + + return str; +@@ -124,8 +125,6 @@ free_mode_list(struct wl_list *mode_list) + void + transmitter_output_destroy(struct weston_transmitter_output *output) + { +- weston_log("Transmitter destroying output '%s'\n", output->base.name); +- + wl_list_remove(&output->link); + + free_mode_list(&output->base.mode_list); +@@ -145,46 +144,150 @@ transmitter_output_destroy_(struct weston_output *base) + transmitter_output_destroy(output); + } + ++ + static void + transmitter_start_repaint_loop(struct weston_output *base) + { +- weston_log("%s(%s)\n", __func__, base->name); ++ struct timespec ts; ++ struct weston_transmitter_output *output = to_transmitter_output(base); ++ ++ weston_compositor_read_presentation_clock(output->base.compositor, &ts); ++ weston_output_finish_frame(&output->base, &ts, 0); ++} ++ ++static int ++transmitter_check_output(struct weston_transmitter_surface *txs, ++ struct weston_compositor *compositor) ++{ ++ struct weston_output *def_output = container_of(compositor->output_list.next, ++ struct weston_output, link); ++ struct weston_view *view; ++ ++ wl_list_for_each_reverse(view, &compositor->view_list, link) { ++ if (view->output == def_output) { ++ if (view->surface == txs->surface) ++ return 1; ++ } ++ } ++ ++ return 0; + } + + static int + transmitter_output_repaint(struct weston_output *base, + pixman_region32_t *damage) + { +- weston_log("%s(%s)\n", __func__, base->name); ++ struct weston_transmitter_output* output = to_transmitter_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; ++ ++ if (!output->from_frame_signal) ++ return 0; ++ ++ output->from_frame_signal = false; ++ ++ /* ++ * 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; ++ ++ 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 (!transmitter_check_output(txs, compositor)) ++ break; ++ ++ if (!txs->wthp_surf) ++ transmitter_api->surface_push_to_remote ++ (view->surface, remote, NULL); ++ transmitter_api->surface_gather_state(txs); ++ break; ++ } ++ } ++ if (!found_surface) ++ transmitter_api->surface_push_to_remote(view->surface, ++ remote, NULL); ++ } ++ } ++ if (!found_output) ++ goto out; + +- return -1; ++ return 0; ++ ++out: ++ transmitter_start_repaint_loop(base); ++ ++ return 0; ++} ++ ++static void ++transmitter_output_enable(struct weston_output *base) ++{ ++ struct weston_transmitter_output *output = to_transmitter_output(base); ++ ++ ++ output->base.assign_planes = NULL; ++ output->base.set_backlight = NULL; ++ output->base.set_dpms = NULL; ++ output->base.switch_mode = NULL; ++} ++ ++static void ++transmitter_output_frame_handler(struct wl_listener *listener, void *data) ++{ ++ struct weston_transmitter_output *output; ++ int ret; ++ ++ output = container_of(listener, struct weston_transmitter_output, ++ frame_listener); ++ output->from_frame_signal = true; ++ ++ ret = transmitter_output_repaint(&output->base, NULL); + } + + int +-transmitter_remote_create_output( +- struct weston_transmitter_remote *remote, +- const struct weston_transmitter_output_info *info) ++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); + + /* +@@ -200,7 +303,7 @@ transmitter_remote_create_output( + * 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_; +@@ -212,13 +315,19 @@ transmitter_remote_create_output( + + 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); + +- weston_log("Transmitter created output '%s': %s, %s, %s\n", +- output->base.name, output->base.make, output->base.model, +- output->base.serial_number); ++ weston_output_enable(&output->base); ++ ++ output->frame_listener.notify = transmitter_output_frame_handler; ++ def_output = container_of(txr->compositor->output_list.next, ++ struct weston_output, link); ++ wl_signal_add(&def_output->frame_signal, &output->frame_listener); ++ output->from_frame_signal = false; + + return 0; + +diff --git a/transmitter/plugin.c b/transmitter/plugin.c +index c5e56d3..1ebd1ef 100644 +--- a/transmitter/plugin.c ++++ b/transmitter/plugin.c +@@ -1,5 +1,6 @@ + /* + * Copyright (C) 2016 DENSO CORPORATION ++ * 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 +@@ -34,8 +35,23 @@ + #include "helpers.h" + #include "timespec-util.h" + ++#include "compositor/weston.h" + #include "plugin.h" + #include "transmitter_api.h" ++#include "plugin-registry.h" ++#include "ivi-shell/ivi-layout-export.h" ++ ++/* waltham */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 +@@ -69,63 +85,6 @@ transmitter_surface_ivi_resize(struct weston_transmitter_surface *txs, + txs->resize_handler(txs->resize_handler_data, width, height); + } + +-static int +-frame_callback_handler(void *data) /* fake */ +-{ +- struct weston_transmitter_surface *txs = data; +- struct weston_frame_callback *cb, *cnext; +- struct weston_output *output; +- struct weston_compositor *compositor; +- uint32_t frame_time; +- uint32_t presented_flags; +- int32_t refresh_nsec; +- struct timespec stamp; +- +- compositor = txs->remote->transmitter->compositor; +- output = txs->sync_output; +- +- /* wl_surface.enter should arrive before any frame callbacks, +- * but remote might send frame callbacks for non-visible too. +- */ +- if (!output) +- return 0; +- +- /* XXX: eeeew */ +- frame_time = weston_compositor_get_time(); +- +- wl_list_for_each_safe(cb, cnext, &txs->frame_callback_list, link) { +- wl_callback_send_done(cb->resource, frame_time); +- wl_resource_destroy(cb->resource); +- } +- +- presented_flags = 0; +- refresh_nsec = millihz_to_nsec(output->current_mode->refresh); +- /* XXX: waaahhhahaa */ +- weston_compositor_read_presentation_clock(compositor, &stamp); +- weston_presentation_feedback_present_list(&txs->feedback_list, +- output, refresh_nsec, &stamp, +- output->msc, +- presented_flags); +- +- return 0; +-} +- +-static void +-fake_frame_callback(struct weston_transmitter_surface *txs) +-{ +- struct weston_transmitter *txr = txs->remote->transmitter; +- struct wl_event_loop *loop; +- +- if (!txs->frame_timer) { +- loop = wl_display_get_event_loop(txr->compositor->wl_display); +- txs->frame_timer = +- wl_event_loop_add_timer(loop, +- frame_callback_handler, txs); +- } +- +- wl_event_source_timer_update(txs->frame_timer, 85); +-} +- + static void + transmitter_surface_configure(struct weston_transmitter_surface *txs, + int32_t dx, int32_t dy) +@@ -139,37 +98,75 @@ transmitter_surface_configure(struct weston_transmitter_surface *txs, + } + + static void +-transmitter_surface_gather_state(struct weston_transmitter_surface *txs) ++buffer_send_complete(struct wthp_buffer *b, uint32_t serial) + { +- weston_log("Transmitter: update surface %p (%d, %d), %d cb\n", +- txs->surface, txs->attach_dx, txs->attach_dy, +- wl_list_length(&txs->surface->frame_callback_list)); +- +- wl_list_insert_list(&txs->frame_callback_list, +- &txs->surface->frame_callback_list); +- wl_list_init(&txs->surface->frame_callback_list); +- +- wl_list_insert_list(&txs->feedback_list, &txs->surface->feedback_list); +- wl_list_init(&txs->surface->feedback_list); +- +- /* TODO: transmit surface state to remote */ +- +- txs->attach_dx = 0; +- txs->attach_dy = 0; ++ if (b) ++ wthp_buffer_destroy(b); + } + +-/** weston_surface apply state signal handler */ ++static const struct wthp_buffer_listener buffer_listener = { ++ buffer_send_complete ++}; ++ + static void +-transmitter_surface_apply_state(struct wl_listener *listener, void *data) ++transmitter_surface_gather_state(struct weston_transmitter_surface *txs) + { +- struct weston_transmitter_surface *txs = +- container_of(listener, struct weston_transmitter_surface, +- apply_state_listener); +- +- assert(data == NULL); ++ struct weston_transmitter_remote *remote = txs->remote; ++ struct waltham_display *dpy = remote->display; + +- transmitter_surface_gather_state(txs); +- fake_frame_callback(txs); ++ if(!dpy->running) { ++ if(remote->status != WESTON_TRANSMITTER_CONNECTION_DISCONNECTED) { ++ remote->status = WESTON_TRANSMITTER_CONNECTION_DISCONNECTED; ++ 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 width = 100; ++ int32_t height = 100; ++ int32_t stride; ++ int ret = 0; ++ void *pixels; ++ ++// stride = surf->width * (PIXMAN_FORMAT_BPP(comp->read_format) / 8); ++ stride = width * (PIXMAN_FORMAT_BPP(comp->read_format) / 8); ++// weston_log("width %d\n", surf->width); ++// weston_log("height %d\n", surf->height); ++// weston_log("stride %d\n", stride); ++ pixels = malloc(stride * height); ++ ++ ret = weston_surface_copy_content(surf, pixels, ++ (stride * height), 0, 0, ++ width, height); ++ if(ret < 0) ++ fprintf(stderr, "failed to get surface content\n"); ++ ++ /* fake sending buffer */ ++ txs->wthp_buf = wthp_blob_factory_create_buffer(remote->display->blob_factory, ++ (stride * height), ++ pixels, ++ width, ++ 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_damage(txs->wthp_surf, txs->attach_dx, txs->attach_dy, width, 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. +@@ -181,8 +178,7 @@ transmitter_surface_apply_state(struct wl_listener *listener, void *data) + static void + transmitter_surface_zombify(struct weston_transmitter_surface *txs) + { +- struct weston_frame_callback *framecb, *cnext; +- ++ struct weston_transmitter_remote *remote; + /* may be called multiple times */ + if (!txs->surface) + return; +@@ -190,20 +186,17 @@ transmitter_surface_zombify(struct weston_transmitter_surface *txs) + wl_signal_emit(&txs->destroy_signal, txs); + + wl_list_remove(&txs->surface_destroy_listener.link); +- weston_log("Transmitter unbound surface %p.\n", txs->surface); + txs->surface = NULL; + + wl_list_remove(&txs->sync_output_destroy_listener.link); +- wl_list_remove(&txs->apply_state_listener.link); +- +- if (txs->map_timer) +- wl_event_source_remove(txs->map_timer); +- if (txs->frame_timer) +- wl_event_source_remove(txs->frame_timer); + +- weston_presentation_feedback_discard_list(&txs->feedback_list); +- wl_list_for_each_safe(framecb, cnext, &txs->frame_callback_list, link) +- wl_resource_destroy(framecb->resource); ++ 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; +@@ -231,25 +224,6 @@ transmitter_surface_destroyed(struct wl_listener *listener, void *data) + transmitter_surface_zombify(txs); + } + +-static struct weston_transmitter_surface * +-transmitter_surface_get(struct weston_surface *ws) +-{ +- struct wl_listener *listener; +- struct weston_transmitter_surface *txs; +- +- listener = wl_signal_get(&ws->destroy_signal, +- transmitter_surface_destroyed); +- +- if (!listener) +- return NULL; +- +- txs = container_of(listener, struct weston_transmitter_surface, +- surface_destroy_listener); +- assert(ws == txs->surface); +- +- return txs; +-} +- + static void + sync_output_destroy_handler(struct wl_listener *listener, void *data) + { +@@ -265,84 +239,48 @@ sync_output_destroy_handler(struct wl_listener *listener, void *data) + } + + static void +-fake_input(struct weston_transmitter_surface *txs) +-{ +- struct wl_list *seat_list = &txs->remote->seat_list; +- struct weston_transmitter_seat *seat; +- +- assert(wl_list_length(seat_list) == 1); +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); +- +- transmitter_seat_fake_pointer_input(seat, txs); +-} +- +-/* fake receiving wl_surface.enter(output) */ +-static int +-map_timer_handler(void *data) +-{ +- struct weston_transmitter_surface *txs = data; +- struct weston_transmitter_output *output; +- +- assert(!wl_list_empty(&txs->remote->output_list)); +- +- output = container_of(txs->remote->output_list.next, +- struct weston_transmitter_output, link); +- +- txs->sync_output = &output->base; +- txs->sync_output_destroy_listener.notify = sync_output_destroy_handler; +- wl_list_remove(&txs->sync_output_destroy_listener.link); +- wl_signal_add(&txs->sync_output->destroy_signal, +- &txs->sync_output_destroy_listener); +- +- weston_surface_force_output(txs->surface, txs->sync_output); +- +- weston_log("Transmitter: surface %p entered output %s\n", +- txs->surface, txs->sync_output->name); +- +- fake_frame_callback(txs); +- fake_input(txs); +- +- return 0; +-} +- +-/* Fake a delay for the remote end to map the surface to an output */ +-static void +-fake_output_mapping(struct weston_transmitter_surface *txs) +-{ +- struct weston_transmitter *txr = txs->remote->transmitter; +- struct wl_event_loop *loop; +- +- loop = wl_display_get_event_loop(txr->compositor->wl_display); +- txs->map_timer = wl_event_loop_add_timer(loop, map_timer_handler, txs); +- wl_event_source_timer_update(txs->map_timer, 400); +-} +- +-/* Fake getting "connection established" from the content streamer. */ +-static void +-fake_stream_opening_handler(void *data) +-{ +- struct weston_transmitter_surface *txs = data; +- +- /* ...once the connection is up: */ +- txs->status = WESTON_TRANSMITTER_STREAM_LIVE; +- wl_signal_emit(&txs->stream_status_signal, txs); +- +- /* need to create the surface on the remote and set all state */ +- transmitter_surface_gather_state(txs); +- +- fake_output_mapping(txs); +-} +- +-/* Fake a callback from content streamer. */ +-static void +-fake_stream_opening(struct weston_transmitter_surface *txs) ++transmitter_surface_set_ivi_id(struct weston_transmitter_surface *txs) + { +- struct weston_transmitter *txr = txs->remote->transmitter; +- struct wl_event_loop *loop; +- +- loop = wl_display_get_event_loop(txr->compositor->wl_display); +- wl_event_loop_add_idle(loop, fake_stream_opening_handler, 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 * +@@ -350,39 +288,58 @@ 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 (transmitter_surface_get(ws)) { +- weston_log("Transmitter: surface %p already bound.\n", ws); ++ if (remote->status != WESTON_TRANSMITTER_CONNECTION_READY) ++ { + return NULL; + } + +- txs = zalloc(sizeof (*txs)); +- if (!txs) +- return NULL; ++ wl_list_for_each(txs, &remote->surface_list, link) { ++ if (txs->surface == ws) { ++ found = true; ++ break; ++ } ++ } + +- txs->remote = remote; +- wl_signal_init(&txs->destroy_signal); +- wl_list_insert(&remote->surface_list, &txs->link); ++ if (!found) { ++ txs = NULL; ++ txs = zalloc(sizeof (*txs)); ++ if (!txs) ++ return NULL; + +- txs->status = WESTON_TRANSMITTER_STREAM_INITIALIZING; +- wl_signal_init(&txs->stream_status_signal); +- wl_signal_add(&txs->stream_status_signal, stream_status); ++ txs->remote = remote; ++ wl_signal_init(&txs->destroy_signal); ++ wl_list_insert(&remote->surface_list, &txs->link); + +- txs->surface = ws; +- txs->surface_destroy_listener.notify = transmitter_surface_destroyed; +- wl_signal_add(&ws->destroy_signal, &txs->surface_destroy_listener); ++ 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->apply_state_listener.notify = transmitter_surface_apply_state; +- wl_signal_add(&ws->apply_state_signal, &txs->apply_state_listener); ++ 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->sync_output_destroy_listener.link); + +- wl_list_init(&txs->frame_callback_list); +- wl_list_init(&txs->feedback_list); ++ 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... */ +- fake_stream_opening(txs); ++ 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; + } +@@ -393,17 +350,53 @@ transmitter_surface_get_stream_status(struct weston_transmitter_surface *txs) + return txs->status; + } + +-static int +-conn_timer_handler(void *data) /* fake */ ++/* 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 weston_transmitter_remote *remote = data; ++ 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 = ++ container_of(l, struct weston_transmitter_remote, ++ establish_listener); + struct weston_transmitter_output_info info = { + WL_OUTPUT_SUBPIXEL_NONE, + WL_OUTPUT_TRANSFORM_NORMAL, + 1, + 0, 0, + 300, 200, +- "fake", ++ strdup(remote->model), + { + WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, + 800, 600, +@@ -411,52 +404,303 @@ conn_timer_handler(void *data) /* fake */ + { NULL, NULL } + } + }; +- +- weston_log("Transmitter connected to %s.\n", remote->addr); +- remote->status = WESTON_TRANSMITTER_CONNECTION_READY; +- wl_signal_emit(&remote->connection_status_signal, remote); +- +- wl_event_source_remove(remote->conn_timer); +- remote->conn_timer = 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 = container_of(w, struct waltham_display, 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; ++ ++ 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; ++ perror("EPOLL_CTL_DEL\n"); ++ ++ return; ++ } ++ } ++ ++ if (events & EPOLLHUP) { ++ fprintf(stderr, "Connection hung up.\n"); ++ dpy->running = false; ++ ++ return; ++ } ++} ++ ++static void ++waltham_mainloop(int fd, uint32_t mask, void *data) ++{ ++ struct weston_transmitter_remote *remote = data; ++ struct watch *w; ++ int count; ++ int i; ++ 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) ++ goto not_running; ++ ++ if (!dpy->running) ++ goto not_running; ++ ++ running_display++; ++ /* Dispatch queued events. */ ++ ++ ret = wth_connection_dispatch(dpy->connection); ++ if (ret < 0) ++ dpy->running = false; ++ 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); ++ } ++ wl_event_source_remove(remote->source); ++ remote->source = wl_event_loop_add_fd(remote->transmitter->loop, ++ remote->display->conn_watch.fd, ++ WL_EVENT_READABLE, ++ waltham_mainloop, remote); ++ ++not_running: ++ ; ++} ++ ++/* A one-off asynchronous open-coded roundtrip handler. */ ++static void ++bling_done(struct wthp_callback *cb, uint32_t arg) ++{ ++ fprintf(stderr, "...sync done.\n"); ++ ++ wthp_callback_free(cb); ++} ++ ++static const struct wthp_callback_listener bling_listener = { ++ bling_done ++}; ++ ++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->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, ®istry_listener, dpy); ++ ++ /* Roundtrip ensures all globals' ads have been received. */ ++ if (wth_connection_roundtrip(dpy->connection) < 0) { ++ fprintf(stderr, "Roundtrip failed.\n"); ++ return -1; ++ } ++ ++ if (!dpy->compositor) { ++ fprintf(stderr, "Did not find wthp_compositor, quitting.\n"); ++ return -1; ++ } ++ ++ /* A one-off asynchronous roundtrip, just for fun. */ ++ fprintf(stderr, "sending wth_display.sync...\n"); ++ dpy->bling = wth_display_sync(dpy->display); ++ wthp_callback_set_listener(dpy->bling, &bling_listener, dpy); ++ ++ dpy->running = true; + + return 0; + } + +-static struct weston_transmitter_remote * +-transmitter_connect_to_remote(struct weston_transmitter *txr, +- const char *addr, +- struct wl_listener *status) ++static int ++establish_timer_handler(void *data) + { +- struct weston_transmitter_remote *remote; +- struct wl_event_loop *loop; ++ struct weston_transmitter_remote *remote = data; ++ int ret; + +- remote = zalloc(sizeof (*remote)); +- if (!remote) +- return NULL; ++ 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; ++} + +- remote->transmitter = txr; +- wl_list_insert(&txr->remote_list, &remote->link); +- remote->addr = strdup(addr); +- remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; +- wl_signal_init(&remote->connection_status_signal); +- wl_signal_add(&remote->connection_status_signal, status); +- wl_list_init(&remote->output_list); +- wl_list_init(&remote->surface_list); +- wl_list_init(&remote->seat_list); ++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); ++ free(txs->wthp_surf); ++ txs->wthp_ivi_surface = NULL; ++ txs->wthp_surf = NULL; ++ } ++} + +- /* XXX: actually start connecting */ +- weston_log("Transmitter connecting to %s...\n", addr); +- /* fake it with a one second timer */ +- loop = wl_display_get_event_loop(txr->compositor->wl_display); +- remote->conn_timer = wl_event_loop_add_timer(loop, conn_timer_handler, +- remote); +- wl_event_source_timer_update(remote->conn_timer, 1000); ++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; + } +@@ -481,10 +725,6 @@ transmitter_remote_destroy(struct weston_transmitter_remote *remote) + * the desctruction order between the shell and Transmitter is + * undefined. + */ +- weston_log("Transmitter disconnecting from %s.\n", remote->addr); +- +- if (remote->conn_timer) +- wl_event_source_remove(remote->conn_timer); + + if (!wl_list_empty(&remote->surface_list)) + weston_log("Transmitter warning: surfaces remain in %s.\n", +@@ -502,6 +742,8 @@ transmitter_remote_destroy(struct weston_transmitter_remote *remote) + free(remote->addr); + wl_list_remove(&remote->link); + ++ wl_event_source_remove(remote->source); ++ + free(remote); + } + +@@ -531,7 +773,6 @@ transmitter_compositor_destroyed(struct wl_listener *listener, void *data) + */ + wl_list_remove(&txr->remote_list); + +- weston_log("Transmitter terminating.\n"); + free(txr); + } + +@@ -553,6 +794,19 @@ transmitter_get(struct weston_compositor *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, +@@ -562,20 +816,12 @@ static const struct weston_transmitter_api transmitter_api_impl = { + 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_ivi_id(struct weston_transmitter_surface *txs, +- uint32_t ivi_id) +-{ +- assert(txs->surface); +- if (!txs->surface) +- return; +- +- weston_log("%s(%p, %#x)\n", __func__, txs->surface, ivi_id); +-} +- +-static void + transmitter_surface_set_resize_callback( + struct weston_transmitter_surface *txs, + weston_transmitter_ivi_resize_handler_t cb, +@@ -586,10 +832,108 @@ transmitter_surface_set_resize_callback( + } + + static const struct weston_transmitter_ivi_api transmitter_ivi_api_impl = { +- transmitter_surface_set_ivi_id, + transmitter_surface_set_resize_callback, + }; + ++static int ++transmitter_create_remote(struct weston_transmitter *txr, ++ const char *model, ++ const char *addr, ++ const char *port, ++ const char *width, ++ const char *height) ++{ ++ struct weston_transmitter_remote *remote; ++ ++ remote = zalloc(sizeof (*remote)); ++ if (!remote) ++ return -1; ++ ++ remote->transmitter = txr; ++ wl_list_insert(&txr->remote_list, &remote->link); ++ remote->model = strdup(model); ++ remote->addr = strdup(addr); ++ remote->port = strdup(port); ++ 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; ++} ++ ++static void ++transmitter_get_server_config(struct weston_transmitter *txr) ++{ ++ 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, §ion, &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"); ++ } ++ } ++ } ++} ++ ++static void ++transmitter_post_init(void *data) ++{ ++ struct weston_transmitter *txr = data; ++ struct weston_transmitter_remote *remote; ++ ++ if (!txr) { ++ weston_log("Transmitter disabled\n"); ++ } else { ++ transmitter_get_server_config(txr); ++ transmitter_connect_to_remote(txr); ++ ++ wl_list_for_each(remote, &txr->remote_list, link) { ++ remote->source = wl_event_loop_add_fd(txr->loop, ++ remote->display->conn_watch.fd, ++ WL_EVENT_READABLE, ++ waltham_mainloop, remote); ++ } ++ } ++} ++ + WL_EXPORT int + wet_module_init(struct weston_compositor *compositor, int *argc, char *argv[]) + { +@@ -628,6 +972,9 @@ wet_module_init(struct weston_compositor *compositor, int *argc, char *argv[]) + + weston_log("Transmitter initialized.\n"); + ++ txr->loop = wl_display_get_event_loop(compositor->wl_display); ++ wl_event_loop_add_idle(txr->loop, transmitter_post_init, txr); ++ + return 0; + + fail: +diff --git a/transmitter/plugin.h b/transmitter/plugin.h +index 710b543..48f49b8 100644 +--- a/transmitter/plugin.h ++++ b/transmitter/plugin.h +@@ -1,5 +1,6 @@ + /* + * Copyright (C) 2016 DENSO CORPORATION ++ * 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 +@@ -32,33 +33,109 @@ + */ + + #include ++#include + + #include "compositor.h" + #include "transmitter_api.h" ++#include "ivi-shell/ivi-layout-export.h" ++ ++#include ++ ++ ++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_event_source *conn_timer; /* fake */ ++ 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 */ +@@ -69,7 +146,7 @@ struct weston_transmitter_surface { + + struct weston_surface *surface; + struct wl_listener surface_destroy_listener; +- struct wl_listener apply_state_listener; ++ const struct ivi_layout_interface *lyt; + + weston_transmitter_ivi_resize_handler_t resize_handler; + void *resize_handler_data; +@@ -77,13 +154,17 @@ struct weston_transmitter_surface { + struct weston_output *sync_output; + struct wl_listener sync_output_destroy_listener; + +- struct wl_event_source *map_timer; /* fake */ +- struct wl_event_source *frame_timer; /* fake */ +- + 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 { +@@ -103,12 +184,28 @@ struct weston_transmitter_output_info { + 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 wl_listener frame_listener; ++ ++ bool from_frame_signal; + }; + + struct weston_transmitter_seat { +- struct weston_seat base; ++ struct weston_seat *base; + struct wl_list link; + + /* pointer */ +@@ -124,8 +221,28 @@ struct weston_transmitter_seat { + 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 +@@ -203,5 +320,14 @@ 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/transmitter/transmitter_api.h b/transmitter/transmitter_api.h +index 95d82ec..b28f946 100644 +--- a/transmitter/transmitter_api.h ++++ b/transmitter/transmitter_api.h +@@ -1,5 +1,6 @@ + /* + * Copyright (C) 2016 DENSO CORPORATION ++ * 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 +@@ -90,7 +91,6 @@ struct weston_transmitter_api { + * Connect to a remote server via Transmitter. + * + * \param txr The Transmitter context. +- * \param addr Address of the remote server. + * \param status Listener to inform of connection status changes. + * \return A handle to the remote connection, or NULL on failure. + * +@@ -102,12 +102,9 @@ struct weston_transmitter_api { + * returned by this function. Use remote_get_status() to fetch the + * current status. + * +- * The address argument is a string in the form "host:port". + */ + struct weston_transmitter_remote * +- (*connect_to_remote)(struct weston_transmitter *txr, +- const char *addr, +- struct wl_listener *status); ++ (*connect_to_remote)(struct weston_transmitter *txr); + + /** + * Retrieve the connection status. +@@ -191,6 +188,25 @@ struct weston_transmitter_api { + 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 * +diff --git a/transmitter/weston.ini.transmitter b/transmitter/weston.ini.transmitter +new file mode 100644 +index 0000000..1aff0b2 +--- /dev/null ++++ b/transmitter/weston.ini.transmitter +@@ -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 +-- +2.7.4 + diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0020-compositor-add-output-type-to-weston_output.patch b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0020-compositor-add-output-type-to-weston_output.patch new file mode 100644 index 000000000..4c46ec4ec --- /dev/null +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0020-compositor-add-output-type-to-weston_output.patch @@ -0,0 +1,281 @@ +From 99fb36e62d3d0e3bda3d2984f280f534a629f70c Mon Sep 17 00:00:00 2001 +From: Wataru Mizuno +Date: Thu, 12 Oct 2017 14:55:13 +0900 +Subject: [PATCH 1/5] compositor: add output type to weston_output + +This enables weston to use multiple types of backend +Each backends have own output structure for each functions +To avoid invalid member access, type identifier is needed + +Signed-off-by: Wataru Mizuno +--- + libweston/compositor-drm.c | 100 +++++++++++++++++++++++----------------- + libweston/compositor-fbdev.c | 1 + + libweston/compositor-headless.c | 1 + + libweston/compositor-rdp.c | 1 + + libweston/compositor-wayland.c | 1 + + libweston/compositor-x11.c | 1 + + libweston/compositor.h | 12 +++++ + 7 files changed, 74 insertions(+), 43 deletions(-) + +diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c +index 1d38f05..0b5b4c4 100644 +--- a/libweston/compositor-drm.c ++++ b/libweston/compositor-drm.c +@@ -243,14 +243,16 @@ drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id) + struct drm_output *output; + + wl_list_for_each(output, &b->compositor->output_list, base.link) { +- if (output->crtc_id == crtc_id) +- return output; ++ if(output->base.output_type == OUTPUT_DRM) ++ if (output->crtc_id == crtc_id) ++ return output; + } + + wl_list_for_each(output, &b->compositor->pending_output_list, + base.link) { +- if (output->crtc_id == crtc_id) +- return output; ++ if(output->base.output_type == OUTPUT_DRM) ++ if (output->crtc_id == crtc_id) ++ return output; + } + + return NULL; +@@ -262,14 +264,16 @@ drm_output_find_by_connector(struct drm_backend *b, uint32_t connector_id) + struct drm_output *output; + + wl_list_for_each(output, &b->compositor->output_list, base.link) { +- if (output->connector_id == connector_id) +- return output; ++ if(output->base.output_type == OUTPUT_DRM) ++ if (output->connector_id == connector_id) ++ return output; + } + + wl_list_for_each(output, &b->compositor->pending_output_list, + base.link) { +- if (output->connector_id == connector_id) +- return output; ++ if(output->base.output_type == OUTPUT_DRM) ++ if (output->connector_id == connector_id) ++ return output; + } + + return NULL; +@@ -2433,6 +2437,7 @@ drm_output_enable(struct weston_output *base) + struct weston_mode *m; + + output->dpms_prop = drm_get_prop(b->drm.fd, output->connector, "DPMS"); ++ output->base.output_type = OUTPUT_DRM; + + if (b->use_pixman) { + if (drm_output_init_pixman(output, b) < 0) { +@@ -2797,38 +2802,42 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device) + + wl_list_for_each_safe(output, next, &b->compositor->output_list, + base.link) { +- bool disconnected = true; +- +- for (i = 0; i < resources->count_connectors; i++) { +- if (connected[i] == output->connector_id) { +- disconnected = false; +- break; ++ if (output->base.output_type == OUTPUT_DRM) { ++ bool disconnected = true; ++ ++ for (i = 0; i < resources->count_connectors; i++) { ++ if (connected[i] == output->connector_id) { ++ disconnected = false; ++ break; ++ } + } +- } + +- if (!disconnected) +- continue; ++ if (!disconnected) ++ continue; + +- weston_log("connector %d disconnected\n", output->connector_id); +- drm_output_destroy(&output->base); ++ weston_log("connector %d disconnected\n", output->connector_id); ++ drm_output_destroy(&output->base); ++ } + } + + wl_list_for_each_safe(output, next, &b->compositor->pending_output_list, + base.link) { +- bool disconnected = true; +- +- for (i = 0; i < resources->count_connectors; i++) { +- if (connected[i] == output->connector_id) { +- disconnected = false; +- break; ++ if (output->base.output_type == OUTPUT_DRM) { ++ bool disconnected = true; ++ ++ for (i = 0; i < resources->count_connectors; i++) { ++ if (connected[i] == output->connector_id) { ++ disconnected = false; ++ break; ++ } + } +- } + +- if (!disconnected) +- continue; ++ if (!disconnected) ++ continue; + +- weston_log("connector %d disconnected\n", output->connector_id); +- drm_output_destroy(&output->base); ++ weston_log("connector %d disconnected\n", output->connector_id); ++ drm_output_destroy(&output->base); ++ } + } + + free(connected); +@@ -2925,18 +2934,21 @@ session_notify(struct wl_listener *listener, void *data) + * pending frame callbacks. */ + + wl_list_for_each(output, &compositor->output_list, base.link) { +- output->base.repaint_needed = 0; +- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0); ++ if(output->base.output_type == OUTPUT_DRM) { ++ output->base.repaint_needed = 0; ++ drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0); ++ } ++ } ++ if(output->base.output_type == OUTPUT_DRM) { ++ output = container_of(compositor->output_list.next, ++ struct drm_output, base.link); ++ ++ wl_list_for_each(sprite, &b->sprite_list, link) ++ drmModeSetPlane(b->drm.fd, ++ sprite->plane_id, ++ output->crtc_id, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0); + } +- +- output = container_of(compositor->output_list.next, +- struct drm_output, base.link); +- +- wl_list_for_each(sprite, &b->sprite_list, link) +- drmModeSetPlane(b->drm.fd, +- sprite->plane_id, +- output->crtc_id, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0); + }; + } + +@@ -3148,7 +3160,8 @@ switch_to_gl_renderer(struct drm_backend *b) + } + + wl_list_for_each(output, &b->compositor->output_list, base.link) +- pixman_renderer_output_destroy(&output->base); ++ if(output->base.output_type == OUTPUT_DRM) ++ pixman_renderer_output_destroy(&output->base); + + b->compositor->renderer->destroy(b->compositor); + +@@ -3160,7 +3173,8 @@ switch_to_gl_renderer(struct drm_backend *b) + } + + wl_list_for_each(output, &b->compositor->output_list, base.link) +- drm_output_init_egl(output, b); ++ if(output->base.output_type == OUTPUT_DRM) ++ drm_output_init_egl(output, b); + + b->use_pixman = 0; + +diff --git a/libweston/compositor-fbdev.c b/libweston/compositor-fbdev.c +index 44f0cf5..9cb903e 100644 +--- a/libweston/compositor-fbdev.c ++++ b/libweston/compositor-fbdev.c +@@ -433,6 +433,7 @@ fbdev_output_enable(struct weston_output *base) + int fb_fd; + struct wl_event_loop *loop; + ++ output->base.output_type = OUTPUT_FBDEV; + /* Create the frame buffer. */ + fb_fd = fbdev_frame_buffer_open(output, output->device, &output->fb_info); + if (fb_fd < 0) { +diff --git a/libweston/compositor-headless.c b/libweston/compositor-headless.c +index a1aec6d..b0d5afb 100644 +--- a/libweston/compositor-headless.c ++++ b/libweston/compositor-headless.c +@@ -148,6 +148,7 @@ headless_output_enable(struct weston_output *base) + loop = wl_display_get_event_loop(b->compositor->wl_display); + output->finish_frame_timer = + wl_event_loop_add_timer(loop, finish_frame_handler, output); ++ output->base.output_type = OUTPUT_HEADLESS; + + if (b->use_pixman) { + output->image_buf = malloc(output->base.current_mode->width * +diff --git a/libweston/compositor-rdp.c b/libweston/compositor-rdp.c +index d9668e8..d525982 100644 +--- a/libweston/compositor-rdp.c ++++ b/libweston/compositor-rdp.c +@@ -519,6 +519,7 @@ rdp_output_enable(struct weston_output *base) + struct rdp_backend *b = to_rdp_backend(base->compositor); + struct wl_event_loop *loop; + ++ output->base.output_type = OUTPUT_RDP; + output->shadow_surface = pixman_image_create_bits(PIXMAN_x8r8g8b8, + output->base.current_mode->width, + output->base.current_mode->height, +diff --git a/libweston/compositor-wayland.c b/libweston/compositor-wayland.c +index 9d35ef7..66a0dbf 100644 +--- a/libweston/compositor-wayland.c ++++ b/libweston/compositor-wayland.c +@@ -1164,6 +1164,7 @@ wayland_output_enable(struct weston_output *base) + struct wayland_backend *b = to_wayland_backend(base->compositor); + int ret = 0; + ++ output->base.output_type = OUTPUT_WAYLAND; + weston_log("Creating %dx%d wayland output at (%d, %d)\n", + output->base.current_mode->width, + output->base.current_mode->height, +diff --git a/libweston/compositor-x11.c b/libweston/compositor-x11.c +index f9cb461..fcf39e1 100644 +--- a/libweston/compositor-x11.c ++++ b/libweston/compositor-x11.c +@@ -825,6 +825,7 @@ x11_output_enable(struct weston_output *base) + XCB_EVENT_MASK_STRUCTURE_NOTIFY, + 0 + }; ++ output->base.output_type = OUTPUT_X11; + + if (!b->no_input) + values[0] |= +diff --git a/libweston/compositor.h b/libweston/compositor.h +index 08e728a..51157d0 100644 +--- a/libweston/compositor.h ++++ b/libweston/compositor.h +@@ -146,9 +146,21 @@ enum dpms_enum { + WESTON_DPMS_OFF + }; + ++/* bit compatible with drm definitions. */ ++enum output_type { ++ OUTPUT_DRM, ++ OUTPUT_FBDEV, ++ OUTPUT_HEADLESS, ++ OUTPUT_RDP, ++ OUTPUT_WAYLAND, ++ OUTPUT_X11, ++ OUTPUT_WALTHAM ++}; ++ + struct weston_output { + uint32_t id; + char *name; ++ enum output_type output_type; + + void *renderer_state; + +-- +2.7.4 + diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0021-transmitter-add-output-type-for-waltham-output.patch b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0021-transmitter-add-output-type-for-waltham-output.patch new file mode 100644 index 000000000..63182581f --- /dev/null +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0021-transmitter-add-output-type-for-waltham-output.patch @@ -0,0 +1,32 @@ +From 329b7a0a897af8142871e5c44e0f9bc4b55f2bc6 Mon Sep 17 00:00:00 2001 +From: Wataru Mizuno +Date: Thu, 12 Oct 2017 16:13:58 +0900 +Subject: [PATCH 2/5] transmitter: add output type for waltham output + +Transmitter creates waltham output +This makes weston has several outputs +Since each backends have each output several outputs +makes invalid member access +To avoid it output type should be identified + +Signed-off-by: Wataru Mizuno +--- + transmitter/output.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/transmitter/output.c b/transmitter/output.c +index a3f8ed1..19a3273 100644 +--- a/transmitter/output.c ++++ b/transmitter/output.c +@@ -239,7 +239,7 @@ transmitter_output_enable(struct weston_output *base) + { + struct weston_transmitter_output *output = to_transmitter_output(base); + +- ++ output->base.output_type = OUTPUT_WALTHAM; + output->base.assign_planes = NULL; + output->base.set_backlight = NULL; + output->base.set_dpms = NULL; +-- +2.7.4 + diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0022-transmitter-did-code-cleaning.patch b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0022-transmitter-did-code-cleaning.patch new file mode 100644 index 000000000..bcdd6cbb6 --- /dev/null +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0022-transmitter-did-code-cleaning.patch @@ -0,0 +1,708 @@ +From b93057e8f4f05b33c5eb2c6f06dae3228dbb409e Mon Sep 17 00:00:00 2001 +From: Wataru Mizuno +Date: Tue, 10 Apr 2018 19:36:02 +0900 +Subject: [PATCH 1/2] transmitter: did code clean -Remove unused variables and + functions -Replace container_of to wl_container_of + +Signed-off-by: Wataru Mizuno +--- + transmitter/input.c | 45 ++++-------- + transmitter/output.c | 37 ++++------ + transmitter/plugin.c | 156 +++++++++++++++--------------------------- + transmitter/plugin.h | 3 +- + transmitter/transmitter_api.h | 3 +- + 5 files changed, 87 insertions(+), 157 deletions(-) + +diff --git a/transmitter/input.c b/transmitter/input.c +index eeb7452..6797b6e 100644 +--- a/transmitter/input.c ++++ b/transmitter/input.c +@@ -1,6 +1,5 @@ + /* +- * Copyright (C) 2016 DENSO CORPORATION +- * Copyright (C) 2017 Advanced Driver Information Technology GmbH, Advanced Driver Information Technology Corporation, Robert Bosch GmbH, Robert Bosch Car Multimedia GmbH, DENSO Corporation ++ * 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 +@@ -24,8 +23,6 @@ + * SOFTWARE. + */ + +-#include "config.h" +- + #include + #include + #include +@@ -34,7 +31,6 @@ + #include + + #include "compositor.h" +-#include "helpers.h" + + #include "plugin.h" + #include "transmitter_api.h" +@@ -810,8 +806,7 @@ pointer_handle_enter(struct wthp_pointer *wthp_pointer, + struct weston_transmitter_seat *seat; + struct weston_transmitter_surface *txs; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + wl_list_for_each(txs, &remote->surface_list, link) + { +@@ -836,8 +831,7 @@ pointer_handle_leave(struct wthp_pointer *wthp_pointer, + struct weston_transmitter_seat *seat; + struct weston_transmitter_surface *txs; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + wl_list_for_each(txs, &remote->surface_list, link) + { +@@ -859,8 +853,7 @@ pointer_handle_motion(struct wthp_pointer *wthp_pointer, + struct wl_list *seat_list = &remote->seat_list; + struct weston_transmitter_seat *seat; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + transmitter_seat_pointer_motion(seat, time, + surface_x, +@@ -880,8 +873,7 @@ pointer_handle_button(struct wthp_pointer *wthp_pointer, + struct wl_list *seat_list = &remote->seat_list; + struct weston_transmitter_seat *seat; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + transmitter_seat_pointer_button(seat, serial, + time, button, +@@ -899,8 +891,7 @@ pointer_handle_axis(struct wthp_pointer *wthp_pointer, + struct wl_list *seat_list = &remote->seat_list; + struct weston_transmitter_seat *seat; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + transmitter_seat_pointer_axis(seat, time, + axis, value); +@@ -974,8 +965,7 @@ keyboard_handle_enter(struct wthp_keyboard *wthp_keyboard, + wl_key->alloc = keys->alloc; + wl_key->data = keys->data; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + wl_list_for_each(txs, &remote->surface_list, link) + { +@@ -999,8 +989,7 @@ keyboard_handle_leave(struct wthp_keyboard *wthp_keyboard, + struct weston_transmitter_seat *seat; + struct weston_transmitter_surface *txs; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + wl_list_for_each(txs, &remote->surface_list, link) + { +@@ -1023,8 +1012,7 @@ keyboard_handle_key(struct wthp_keyboard *wthp_keyboard, + struct wl_list *seat_list = &remote->seat_list; + struct weston_transmitter_seat *seat; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + transmitter_seat_keyboard_key(seat, serial, time, key, state); + } +@@ -1073,8 +1061,7 @@ touch_handle_down (struct wthp_touch * wthp_touch, + struct weston_transmitter_seat *seat; + struct weston_transmitter_surface *txs; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + wl_list_for_each(txs, &remote->surface_list, link) + { +@@ -1097,8 +1084,7 @@ touch_handle_up (struct wthp_touch * wthp_touch, + struct wl_list *seat_list = &remote->seat_list; + struct weston_transmitter_seat *seat; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + transmitter_seat_touch_up(seat, serial, time, id); + } +@@ -1116,8 +1102,7 @@ touch_handle_motion (struct wthp_touch * wthp_touch, + struct wl_list *seat_list = &remote->seat_list; + struct weston_transmitter_seat *seat; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + transmitter_seat_touch_motion(seat, time, id, x, y); + } +@@ -1132,8 +1117,7 @@ touch_handle_frame (struct wthp_touch * wthp_touch) + struct wl_list *seat_list = &remote->seat_list; + struct weston_transmitter_seat *seat; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + transmitter_seat_touch_frame(seat); + } +@@ -1147,8 +1131,7 @@ touch_handle_cancel (struct wthp_touch * wthp_touch) + struct wl_list *seat_list = &remote->seat_list; + struct weston_transmitter_seat *seat; + +- seat = container_of(seat_list->next, +- struct weston_transmitter_seat, link); ++ seat = wl_container_of(seat_list->next, seat, link); + + transmitter_seat_touch_cancel(seat); + } +diff --git a/transmitter/output.c b/transmitter/output.c +index 19a3273..003056f 100644 +--- a/transmitter/output.c ++++ b/transmitter/output.c +@@ -1,6 +1,5 @@ + /* +- * Copyright (C) 2016 DENSO CORPORATION +- * Copyright (C) 2017 Advanced Driver Information Technology GmbH, Advanced Driver Information Technology Corporation, Robert Bosch GmbH, Robert Bosch Car Multimedia GmbH, DENSO Corporation ++ * 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 +@@ -24,14 +23,11 @@ + * SOFTWARE. + */ + +-#include "config.h" +- + #include + #include + #include + + #include "compositor.h" +-#include "helpers.h" + + #include "plugin.h" + #include "transmitter_api.h" +@@ -63,12 +59,6 @@ + * exclusive with weston_compositor_add_output(). + */ + +-static inline struct weston_transmitter_output * +-to_transmitter_output(struct weston_output *base) +-{ +- return container_of(base, struct weston_transmitter_output, base); +-} +- + static char * + make_model(struct weston_transmitter_remote *remote, int name) + { +@@ -115,7 +105,7 @@ free_mode_list(struct wl_list *mode_list) + struct weston_mode *mode; + + while (!wl_list_empty(mode_list)) { +- mode = container_of(mode_list->next, struct weston_mode, link); ++ mode = wl_container_of(mode_list->next, mode, link); + + wl_list_remove(&mode->link); + free(mode); +@@ -139,7 +129,7 @@ transmitter_output_destroy(struct weston_transmitter_output *output) + static void + transmitter_output_destroy_(struct weston_output *base) + { +- struct weston_transmitter_output *output = to_transmitter_output(base); ++ struct weston_transmitter_output *output = wl_container_of(base, output, base); + + transmitter_output_destroy(output); + } +@@ -149,7 +139,7 @@ static void + transmitter_start_repaint_loop(struct weston_output *base) + { + struct timespec ts; +- struct weston_transmitter_output *output = to_transmitter_output(base); ++ 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); +@@ -159,8 +149,8 @@ static int + transmitter_check_output(struct weston_transmitter_surface *txs, + struct weston_compositor *compositor) + { +- struct weston_output *def_output = container_of(compositor->output_list.next, +- struct weston_output, link); ++ struct weston_output *def_output = wl_container_of(compositor->output_list.next, ++ def_output, link); + struct weston_view *view; + + wl_list_for_each_reverse(view, &compositor->view_list, link) { +@@ -177,7 +167,7 @@ static int + transmitter_output_repaint(struct weston_output *base, + pixman_region32_t *damage) + { +- struct weston_transmitter_output* output = to_transmitter_output(base); ++ 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 = +@@ -201,6 +191,9 @@ transmitter_output_repaint(struct weston_output *base, + 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) { +@@ -237,9 +230,8 @@ out: + static void + transmitter_output_enable(struct weston_output *base) + { +- struct weston_transmitter_output *output = to_transmitter_output(base); ++ struct weston_transmitter_output *output = wl_container_of(base, output, base); + +- output->base.output_type = OUTPUT_WALTHAM; + output->base.assign_planes = NULL; + output->base.set_backlight = NULL; + output->base.set_dpms = NULL; +@@ -252,8 +244,7 @@ transmitter_output_frame_handler(struct wl_listener *listener, void *data) + struct weston_transmitter_output *output; + int ret; + +- output = container_of(listener, struct weston_transmitter_output, +- frame_listener); ++ output = wl_container_of(listener, output, frame_listener); + output->from_frame_signal = true; + + ret = transmitter_output_repaint(&output->base, NULL); +@@ -324,8 +315,8 @@ transmitter_remote_create_output(struct weston_transmitter_remote *remote, + weston_output_enable(&output->base); + + output->frame_listener.notify = transmitter_output_frame_handler; +- def_output = container_of(txr->compositor->output_list.next, +- struct weston_output, link); ++ def_output = wl_container_of(txr->compositor->output_list.next, ++ def_output, link); + wl_signal_add(&def_output->frame_signal, &output->frame_listener); + output->from_frame_signal = false; + +diff --git a/transmitter/plugin.c b/transmitter/plugin.c +index 1ebd1ef..1f00f33 100644 +--- a/transmitter/plugin.c ++++ b/transmitter/plugin.c +@@ -1,6 +1,5 @@ + /* +- * Copyright (C) 2016 DENSO CORPORATION +- * Copyright (C) 2017 Advanced Driver Information Technology GmbH, Advanced Driver Information Technology Corporation, Robert Bosch GmbH, Robert Bosch Car Multimedia GmbH, DENSO Corporation ++ * 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 +@@ -24,16 +23,12 @@ + * SOFTWARE. + */ + +-#include "config.h" +- + #include + #include + #include + #include + + #include "compositor.h" +-#include "helpers.h" +-#include "timespec-util.h" + + #include "compositor/weston.h" + #include "plugin.h" +@@ -113,10 +108,13 @@ 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); + } + } +@@ -127,43 +125,32 @@ transmitter_surface_gather_state(struct weston_transmitter_surface *txs) + /* waltham */ + struct weston_surface *surf = txs->surface; + struct weston_compositor *comp = surf->compositor; +- int32_t width = 100; +- int32_t height = 100; +- int32_t stride; +- int ret = 0; +- void *pixels; +- +-// stride = surf->width * (PIXMAN_FORMAT_BPP(comp->read_format) / 8); ++ int32_t stride, data_sz, width, height; ++ void *data; ++ ++ width = 1; ++ height = 1; + stride = width * (PIXMAN_FORMAT_BPP(comp->read_format) / 8); +-// weston_log("width %d\n", surf->width); +-// weston_log("height %d\n", surf->height); +-// weston_log("stride %d\n", stride); +- pixels = malloc(stride * height); + +- ret = weston_surface_copy_content(surf, pixels, +- (stride * height), 0, 0, +- width, height); +- if(ret < 0) +- fprintf(stderr, "failed to get surface content\n"); +- ++ data = malloc(stride * height); ++ data_sz = stride * height; ++ + /* fake sending buffer */ + txs->wthp_buf = wthp_blob_factory_create_buffer(remote->display->blob_factory, +- (stride * height), +- pixels, +- width, +- height, ++ 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_damage(txs->wthp_surf, txs->attach_dx, txs->attach_dy, width, height); ++ 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); + ++ wth_connection_flush(remote->display->connection); + txs->attach_dx = 0; + txs->attach_dy = 0; + } +@@ -216,8 +203,7 @@ static void + transmitter_surface_destroyed(struct wl_listener *listener, void *data) + { + struct weston_transmitter_surface *txs = +- container_of(listener, struct weston_transmitter_surface, +- surface_destroy_listener); ++ wl_container_of(listener, txs, surface_destroy_listener); + + assert(data == txs->surface); + +@@ -229,8 +215,7 @@ sync_output_destroy_handler(struct wl_listener *listener, void *data) + { + struct weston_transmitter_surface *txs; + +- txs = container_of(listener, struct weston_transmitter_surface, +- sync_output_destroy_listener); ++ 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); +@@ -364,7 +349,7 @@ registry_handle_global(struct wthp_registry *registry, + 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); +@@ -388,8 +373,7 @@ static void + conn_ready_notify(struct wl_listener *l, void *data) + { + struct weston_transmitter_remote *remote = +- container_of(l, struct weston_transmitter_remote, +- establish_listener); ++ wl_container_of(l, remote, establish_listener); + struct weston_transmitter_output_info info = { + WL_OUTPUT_SUBPIXEL_NONE, + WL_OUTPUT_TRANSFORM_NORMAL, +@@ -441,7 +425,7 @@ static const struct wthp_registry_listener registry_listener = { + static void + connection_handle_data(struct watch *w, uint32_t events) + { +- struct waltham_display *dpy = container_of(w, struct waltham_display, conn_watch); ++ struct waltham_display *dpy = wl_container_of(w, dpy, conn_watch); + struct weston_transmitter_remote *remote = dpy->remote; + int ret; + +@@ -454,7 +438,7 @@ connection_handle_data(struct watch *w, uint32_t events) + if (events & EPOLLERR) { + weston_log("Connection errored out.\n"); + dpy->running = false; +- ++ remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; + return; + } + +@@ -468,10 +452,12 @@ connection_handle_data(struct watch *w, uint32_t events) + 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; +@@ -479,8 +465,9 @@ connection_handle_data(struct watch *w, uint32_t events) + } + + if (events & EPOLLHUP) { +- fprintf(stderr, "Connection hung up.\n"); ++ weston_log("Connection hung up.\n"); + dpy->running = false; ++ remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; + + return; + } +@@ -491,8 +478,6 @@ waltham_mainloop(int fd, uint32_t mask, void *data) + { + struct weston_transmitter_remote *remote = data; + struct watch *w; +- int count; +- int i; + int ret; + int running_display; + running_display = 0; +@@ -503,17 +488,18 @@ waltham_mainloop(int fd, uint32_t mask, void *data) + goto not_running; + + if (!dpy->connection) +- goto not_running; +- ++ dpy->running = false; ++ + if (!dpy->running) + goto not_running; + + running_display++; + /* Dispatch queued events. */ +- + ret = wth_connection_dispatch(dpy->connection); +- if (ret < 0) ++ if (ret < 0) { + dpy->running = false; ++ remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; ++ } + if (!dpy->running) + goto not_running; + +@@ -532,29 +518,11 @@ waltham_mainloop(int fd, uint32_t mask, void *data) + */ + w->cb(w, mask); + } +- wl_event_source_remove(remote->source); +- remote->source = wl_event_loop_add_fd(remote->transmitter->loop, +- remote->display->conn_watch.fd, +- WL_EVENT_READABLE, +- waltham_mainloop, remote); + + not_running: + ; + } + +-/* A one-off asynchronous open-coded roundtrip handler. */ +-static void +-bling_done(struct wthp_callback *cb, uint32_t arg) +-{ +- fprintf(stderr, "...sync done.\n"); +- +- wthp_callback_free(cb); +-} +- +-static const struct wthp_callback_listener bling_listener = { +- bling_done +-}; +- + static int + waltham_client_init(struct waltham_display *dpy) + { +@@ -575,6 +543,10 @@ waltham_client_init(struct waltham_display *dpy) + 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 +@@ -589,19 +561,17 @@ waltham_client_init(struct waltham_display *dpy) + + /* Roundtrip ensures all globals' ads have been received. */ + if (wth_connection_roundtrip(dpy->connection) < 0) { +- fprintf(stderr, "Roundtrip failed.\n"); ++ weston_log("Roundtrip failed.\n"); + return -1; + } + + if (!dpy->compositor) { +- fprintf(stderr, "Did not find wthp_compositor, quitting.\n"); ++ weston_log("Did not find wthp_compositor, quitting.\n"); + return -1; + } + + /* A one-off asynchronous roundtrip, just for fun. */ +- fprintf(stderr, "sending wth_display.sync...\n"); +- dpy->bling = wth_display_sync(dpy->display); +- wthp_callback_set_listener(dpy->bling, &bling_listener, dpy); ++ weston_log("sending wth_display.sync...\n"); + + dpy->running = true; + +@@ -644,8 +614,8 @@ disconnect_surface(struct weston_transmitter_remote *remote) + wl_list_for_each(txs, &remote->surface_list, link) + { + free(txs->wthp_ivi_surface); +- free(txs->wthp_surf); + txs->wthp_ivi_surface = NULL; ++ free(txs->wthp_surf); + txs->wthp_surf = NULL; + } + } +@@ -754,8 +724,7 @@ transmitter_compositor_destroyed(struct wl_listener *listener, void *data) + struct weston_transmitter_remote *remote; + struct weston_transmitter_surface *txs; + struct weston_transmitter *txr = +- container_of(listener, struct weston_transmitter, +- compositor_destroy_listener); ++ wl_container_of(listener, txr, compositor_destroy_listener); + + assert(data == txr->compositor); + +@@ -787,8 +756,7 @@ transmitter_get(struct weston_compositor *compositor) + if (!listener) + return NULL; + +- txr = container_of(listener, struct weston_transmitter, +- compositor_destroy_listener); ++ txr = wl_container_of(listener, txr, compositor_destroy_listener); + assert(compositor == txr->compositor); + + return txr; +@@ -868,9 +836,18 @@ transmitter_create_remote(struct weston_transmitter *txr, + 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; +@@ -913,27 +890,6 @@ transmitter_get_server_config(struct weston_transmitter *txr) + } + } + +-static void +-transmitter_post_init(void *data) +-{ +- struct weston_transmitter *txr = data; +- struct weston_transmitter_remote *remote; +- +- if (!txr) { +- weston_log("Transmitter disabled\n"); +- } else { +- transmitter_get_server_config(txr); +- transmitter_connect_to_remote(txr); +- +- wl_list_for_each(remote, &txr->remote_list, link) { +- remote->source = wl_event_loop_add_fd(txr->loop, +- remote->display->conn_watch.fd, +- WL_EVENT_READABLE, +- waltham_mainloop, remote); +- } +- } +-} +- + WL_EXPORT int + wet_module_init(struct weston_compositor *compositor, int *argc, char *argv[]) + { +@@ -941,9 +897,10 @@ wet_module_init(struct weston_compositor *compositor, int *argc, char *argv[]) + int ret; + + txr = zalloc(sizeof *txr); +- if (!txr) ++ if (!txr){ ++ weston_log("Transmitter disabled\n"); + return -1; +- ++ } + wl_list_init(&txr->remote_list); + + txr->compositor = compositor; +@@ -973,7 +930,8 @@ wet_module_init(struct weston_compositor *compositor, int *argc, char *argv[]) + weston_log("Transmitter initialized.\n"); + + txr->loop = wl_display_get_event_loop(compositor->wl_display); +- wl_event_loop_add_idle(txr->loop, transmitter_post_init, txr); ++ transmitter_get_server_config(txr); ++ transmitter_connect_to_remote(txr); + + return 0; + +diff --git a/transmitter/plugin.h b/transmitter/plugin.h +index 48f49b8..116c1f6 100644 +--- a/transmitter/plugin.h ++++ b/transmitter/plugin.h +@@ -1,6 +1,5 @@ + /* +- * Copyright (C) 2016 DENSO CORPORATION +- * Copyright (C) 2017 Advanced Driver Information Technology GmbH, Advanced Driver Information Technology Corporation, Robert Bosch GmbH, Robert Bosch Car Multimedia GmbH, DENSO Corporation ++ * 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 +diff --git a/transmitter/transmitter_api.h b/transmitter/transmitter_api.h +index b28f946..4a660a0 100644 +--- a/transmitter/transmitter_api.h ++++ b/transmitter/transmitter_api.h +@@ -1,6 +1,5 @@ + /* +- * Copyright (C) 2016 DENSO CORPORATION +- * Copyright (C) 2017 Advanced Driver Information Technology GmbH, Advanced Driver Information Technology Corporation, Robert Bosch GmbH, Robert Bosch Car Multimedia GmbH, DENSO Corporation ++ * 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 +-- +2.7.4 + diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0023-compositor-drm-introduce-drm_get_dmafd_from_view.patch b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0023-compositor-drm-introduce-drm_get_dmafd_from_view.patch new file mode 100644 index 000000000..bec90c75d --- /dev/null +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0023-compositor-drm-introduce-drm_get_dmafd_from_view.patch @@ -0,0 +1,132 @@ +From 3dbffb783f44752ec221a2ee7a94a21934d681a2 Mon Sep 17 00:00:00 2001 +From: Wataru Mizuno +Date: Tue, 10 Apr 2018 12:22:07 +0900 +Subject: [PATCH 5/5] compositor-drm: introduce drm_get_dmafd_from_view + +This API enables to get dmafd from weston_view + +Signed-off-by: Wataru Mizuno +--- + libweston/compositor-drm.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++ + libweston/compositor-drm.h | 7 ++++ + 2 files changed, 87 insertions(+) + +diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c +index 0b5b4c4..77f2ece 100644 +--- a/libweston/compositor-drm.c ++++ b/libweston/compositor-drm.c +@@ -2430,6 +2430,85 @@ drm_output_set_seat(struct weston_output *base, + } + + static int ++drm_get_dma_fd_from_view(struct weston_output *base, ++ struct weston_view *ev) ++{ ++ struct drm_backend *b = to_drm_backend(base->compositor); ++ struct weston_buffer *buffer = ev->surface->buffer_ref.buffer; ++ struct gbm_bo *bo; ++ struct drm_fb *current; ++ struct linux_dmabuf_buffer *dmabuf; ++ uint32_t format; ++ int fd, ret; ++ ++ if(!buffer) { ++ weston_log("buffer is NULL\n"); ++ return -1; ++ } ++ ++ if(dmabuf = linux_dmabuf_buffer_get(buffer->resource)) { ++ struct gbm_import_fd_data gbm_dmabuf = { ++ .fd = dmabuf->attributes.fd[0], ++ .width = dmabuf->attributes.width, ++ .height = dmabuf->attributes.height, ++ .stride = dmabuf->attributes.stride[0], ++ .format = dmabuf->attributes.format ++ }; ++ ++ bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, ++ &gbm_dmabuf, GBM_BO_USE_SCANOUT); ++ if (!bo) { ++ weston_log("failed to get gbm_bo\n"); ++ return -1; ++ } ++ ++ current = zalloc(sizeof *current); ++ current->handle = gbm_bo_get_handle(bo).s32; ++ if (!current->handle) { ++ fprintf(stderr, "failed to get drm_handle\n"); ++ return -1; ++ } ++ } ++ else if(ev->surface->buffer_ref.buffer->legacy_buffer) { ++ bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER, ++ buffer->resource, GBM_BO_USE_SCANOUT); ++ ++ if (!bo) { ++ weston_log("failed to get gbm_bo\n"); ++ return -1; ++ } ++ ++ format = gbm_bo_get_format(bo); ++ if (!format) { ++ weston_log("failed to get format\n"); ++ gbm_bo_destroy(bo); ++ return -1; ++ } ++ ++ current = drm_fb_get_from_bo(bo, b, format); ++ if (!current) { ++ weston_log("failed to get drm_fb\n"); ++ gbm_bo_destroy(bo); ++ return -1; ++ } ++ } ++ else { ++ weston_log("Buffer is not supported\n"); ++ return -1; ++ } ++ ++ ret = drmPrimeHandleToFD(b->drm.fd, current->handle, ++ DRM_CLOEXEC, &fd); ++ free(current); ++ if (ret) { ++ weston_log("failed to create prime fd for front buffer\n"); ++ return -1; ++ } ++ ++ return fd; ++} ++ ++static int + drm_output_enable(struct weston_output *base) + { + struct drm_output *output = to_drm_output(base); +@@ -3199,6 +3278,7 @@ static const struct weston_drm_output_api api = { + drm_output_set_mode, + drm_output_set_gbm_format, + drm_output_set_seat, ++ drm_get_dma_fd_from_view, + }; + + static struct drm_backend * +diff --git a/libweston/compositor-drm.h b/libweston/compositor-drm.h +index 2e2995a..fe00bd5 100644 +--- a/libweston/compositor-drm.h ++++ b/libweston/compositor-drm.h +@@ -78,6 +78,13 @@ struct weston_drm_output_api { + */ + void (*set_seat)(struct weston_output *output, + const char *seat); ++ ++ /** Get the dma fd from drm view. ++ * ++ * The dma fd is got from weston_view. ++ * Returns fd on success, -1 on failure. ++ */ ++ int (*get_dma_fd_from_view)(struct weston_output *output, struct weston_view *view); + }; + + static inline const struct weston_drm_output_api * +-- +2.7.4 + diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0024-transmitter-introduce-waltham-renderer.patch b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0024-transmitter-introduce-waltham-renderer.patch new file mode 100644 index 000000000..a328bde13 --- /dev/null +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/weston/0024-transmitter-introduce-waltham-renderer.patch @@ -0,0 +1,803 @@ +From 0db59bf629def81fe9925fa435ec845e2069dd4b Mon Sep 17 00:00:00 2001 +From: Wataru Mizuno +Date: Wed, 11 Apr 2018 12:19:58 +0900 +Subject: [PATCH] transmitter: introduce waltham-renderer + +The waltham-renderer creates and sends buffer for remote site. +This is using gst-recorder APIs. + +Signed-off-by: Wataru Mizuno +--- + Makefile.am | 12 +++ + transmitter/README | 86 +++++++++++---------- + transmitter/input.c | 2 +- + transmitter/output.c | 104 ++++++++++++++------------ + transmitter/plugin.c | 45 ++++++----- + transmitter/plugin.h | 6 +- + transmitter/transmitter_api.h | 9 +++ + transmitter/waltham-renderer.c | 166 +++++++++++++++++++++++++++++++++++++++++ + transmitter/waltham-renderer.h | 33 ++++++++ + 9 files changed, 347 insertions(+), 116 deletions(-) + create mode 100644 transmitter/waltham-renderer.c + create mode 100644 transmitter/waltham-renderer.h + +diff --git a/Makefile.am b/Makefile.am +index 2cb1920..0af66d6 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -526,6 +526,18 @@ transmitter_la_SOURCES = \ + shared/timespec-util.h \ + shared/zalloc.h \ + src/compositor.h ++ ++module_LTLIBRARIES += waltham-renderer.la ++waltham_renderer_la_LDFLAGS = -module -avoid-version ++waltham_renderer_la_CFLAGS = \ ++ $(COMPOSITOR_CFLAGS) \ ++ $(AM_CFLAGS) \ ++ $(WALTHAM_CFLAGS) ++waltham_renderer_la_LIBADD = $(COMPOSITOR_LIBS) \ ++ -lwaltham ++waltham_renderer_la_SOURCES = \ ++ transmitter/waltham-renderer.c \ ++ transmitter/waltham-renderer.h + endif + + noinst_PROGRAMS += spring-tool +diff --git a/transmitter/README b/transmitter/README +index af80574..345142d 100644 +--- a/transmitter/README ++++ b/transmitter/README +@@ -1,4 +1,4 @@ +-Transmitter plugin ++Transmitter plugin + + The current implementation of Transmitter is a stub which interfaces to + other Weston parts appropriately, but all networking is just a mockup. +@@ -15,8 +15,8 @@ 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'. ++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 +@@ -27,57 +27,66 @@ In details, see 'weston.ini.transmitter'. + + How to test + =========== +-You can use server side test application in waltham repository. ++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: + +- [06:12:41.238] Loading module '/usr/lib64/weston/ivi-shell.so' +- [06:12:41.245] launching '/usr/libexec/weston-keyboard' +- [06:12:41.247] Loading module '/usr/lib64/weston/ivi-controller.so' +- [06:12:41.252] Loading module '/usr/lib64/weston/ivi-input-controller.so' +- [06:12:41.253] ivi-input-controller module loaded successfully! +- [06:12:41.255] Loading module '/usr/lib64/weston/transmitter.so' +- [06:12:41.260] Registered plugin API 'transmitter_v1' of size 88 +- [06:12:41.260] Registered plugin API 'transmitter_ivi_v1' of size 16 +- [06:12:41.260] Transmitter initialized. +- [06:12:41.260] ivi-layout: Transmitter enabled. +- [06:12:41.260] Transmitter weston_seat 0x14f8010 +- [06:12:41.260] Transmitter created pointer=0x139a440 for seat 0x14f8010 +- [06:12:41.261] Transmitter created keyboard=0x14f8160 for seat 0x14f8010 +- [06:12:41.261] Transmitter created touch=0x1508750 for seat 0x14f8010 ++ [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: + +- root@gr-mrb-64:~# debug: wth_connection_insert_new_object: new object id: 1 ++ debug: wth_connection_insert_new_object: new object id: 1 + debug: wth_connection_insert_new_object: new object id: 2 +- 2017-07-19T06:14:31Z 00001000030000000100000002000000 wth_display_get_registry ++ 2018-01-09T13:24:22Z 00001000030000000100000002000000 wth_display_get_registry + debug: wth_connection_insert_new_object: new object id: 3 +- 2017-07-19T06:14:31Z 00001000020000000100000003000000 wth_display_sync +- debug: Message received on conn 0x1560340: (9) 40 bytes ++ 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 +- 2017-07-19T06:14:31Z 00002c000800000002000000010000000400000010000000777468705f636f6d706f7369746f720001000000 wthp_registry_bind +- debug: Message received on conn 0x1560340: (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: 5 +- 2017-07-19T06:14:31Z 000030000800000002000000010000000500000012000000777468705f626c6f625f666163746f72790001000000 wthp_registry_bind +- debug: Message received on conn 0x1560340: (9) 48 bytes ++ 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 +- 2017-07-19T06:14:31Z 000034000800000002000000010000000600000015000000777468705f6976695f6170706c69636174696f6e0001000000 wthp_registry_bind +- debug: Message received on conn 0x1560340: (11) 16 bytes +- debug: wthp_callback_send_done(3, 0) (opcode 11) called. +- sending wth_display.sync... ++ 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 +- 2017-07-19T06:14:31Z 00001000020000000100000007000000 wth_display_sync +- debug: Message received on conn 0x1560340: (11) 16 bytes +- debug: wthp_callback_send_done(7, 0) (opcode 11) called. +- ...sync done. ++ 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 backend output + - Put surface on transmitter output + + Weston log will indicate remoting has started: +@@ -85,5 +94,4 @@ 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 +- ++[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/transmitter/input.c b/transmitter/input.c +index 6797b6e..e00546b 100644 +--- a/transmitter/input.c ++++ b/transmitter/input.c +@@ -964,7 +964,7 @@ keyboard_handle_enter(struct wthp_keyboard *wthp_keyboard, + 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) +diff --git a/transmitter/output.c b/transmitter/output.c +index 003056f..2cca781 100644 +--- a/transmitter/output.c ++++ b/transmitter/output.c +@@ -28,9 +28,12 @@ + #include + + #include "compositor.h" ++#include "compositor-drm.h" ++#include "plugin-registry.h" + + #include "plugin.h" + #include "transmitter_api.h" ++#include "waltham-renderer.h" + + /** @file + * +@@ -59,6 +62,8 @@ + * exclusive with weston_compositor_add_output(). + */ + ++static struct waltham_renderer_interface *waltham_renderer; ++ + static char * + make_model(struct weston_transmitter_remote *remote, int name) + { +@@ -146,45 +151,26 @@ transmitter_start_repaint_loop(struct weston_output *base) + } + + static int +-transmitter_check_output(struct weston_transmitter_surface *txs, +- struct weston_compositor *compositor) +-{ +- struct weston_output *def_output = wl_container_of(compositor->output_list.next, +- def_output, link); +- struct weston_view *view; +- +- wl_list_for_each_reverse(view, &compositor->view_list, link) { +- if (view->output == def_output) { +- if (view->surface == txs->surface) +- return 1; +- } +- } +- +- return 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 = ++ 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; + +- if (!output->from_frame_signal) +- return 0; +- +- output->from_frame_signal = false; ++ 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, ++ * 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. + */ +@@ -201,24 +187,34 @@ transmitter_output_repaint(struct weston_output *base, + wl_list_for_each(txs, &remote->surface_list, link) { + if (txs->surface == view->surface) { + found_surface = true; +- if (!transmitter_check_output(txs, compositor)) +- break; +- + 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; ++ } ++ 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, ++ 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: +@@ -228,28 +224,38 @@ out: + } + + 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 = NULL; ++ output->base.assign_planes = transmitter_assign_planes; + output->base.set_backlight = NULL; + output->base.set_dpms = NULL; + output->base.switch_mode = NULL; + } + +-static void +-transmitter_output_frame_handler(struct wl_listener *listener, void *data) +-{ +- struct weston_transmitter_output *output; +- int ret; +- +- output = wl_container_of(listener, output, frame_listener); +- output->from_frame_signal = true; +- +- ret = transmitter_output_repaint(&output->base, NULL); +-} +- + int + transmitter_remote_create_output(struct weston_transmitter_remote *remote, + const struct weston_transmitter_output_info *info) +@@ -312,13 +318,15 @@ transmitter_remote_create_output(struct weston_transmitter_remote *remote, + output->remote = remote; + wl_list_insert(&remote->output_list, &output->link); + +- weston_output_enable(&output->base); ++ /* 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; ++ } + +- output->frame_listener.notify = transmitter_output_frame_handler; +- def_output = wl_container_of(txr->compositor->output_list.next, +- def_output, link); +- wl_signal_add(&def_output->frame_signal, &output->frame_listener); +- output->from_frame_signal = false; ++ weston_output_enable(&output->base); + + return 0; + +diff --git a/transmitter/plugin.c b/transmitter/plugin.c +index 1f00f33..faf28b5 100644 +--- a/transmitter/plugin.c ++++ b/transmitter/plugin.c +@@ -121,20 +121,20 @@ transmitter_surface_gather_state(struct weston_transmitter_surface *txs) + 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, +@@ -143,13 +143,13 @@ transmitter_surface_gather_state(struct weston_transmitter_surface *txs) + 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; +@@ -255,7 +255,7 @@ transmitter_surface_set_ivi_id(struct weston_transmitter_surface *txs) + 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); +@@ -313,7 +313,7 @@ transmitter_surface_push_to_remote(struct weston_surface *ws, + wl_list_init(&txs->frame_callback_list); + wl_list_init(&txs->feedback_list); + +- txs->lyt = weston_plugin_api_get(txr->compositor, ++ txs->lyt = weston_plugin_api_get(txr->compositor, + IVI_LAYOUT_API_NAME, sizeof(txs->lyt)); + } + +@@ -351,15 +351,15 @@ registry_handle_global(struct wthp_registry *registry, + struct waltham_display *dpy = wth_object_get_user_data((struct wth_object *)registry); + + if (strcmp(interface, "wthp_compositor") == 0) { +- assert(!dpy->compositor); ++ 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); ++ 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); ++ 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) { +@@ -486,13 +486,13 @@ waltham_mainloop(int fd, uint32_t mask, void *data) + 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); +@@ -505,7 +505,7 @@ waltham_mainloop(int fd, uint32_t mask, void *data) + + /* 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. + */ +@@ -570,9 +570,6 @@ waltham_client_init(struct waltham_display *dpy) + return -1; + } + +- /* A one-off asynchronous roundtrip, just for fun. */ +- weston_log("sending wth_display.sync...\n"); +- + dpy->running = true; + + return 0; +@@ -586,7 +583,7 @@ establish_timer_handler(void *data) + + ret = waltham_client_init(remote->display); + if(ret == -2) { +- wl_event_source_timer_update(remote->establish_timer, ++ wl_event_source_timer_update(remote->establish_timer, + ESTABLISH_CONNECTION_PERIOD); + return 0; + } +@@ -631,13 +628,13 @@ retry_timer_handler(void *data) + registry_handle_global_remove(dpy->registry, 1); + init_globals(dpy); + disconnect_surface(remote); +- wl_event_source_timer_update(remote->establish_timer, ++ wl_event_source_timer_update(remote->establish_timer, + ESTABLISH_CONNECTION_PERIOD); + + return 0; + } + else +- wl_event_source_timer_update(remote->retry_timer, ++ wl_event_source_timer_update(remote->retry_timer, + RETRY_CONNECTION_PERIOD); + return 0; + } +@@ -648,7 +645,7 @@ 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 */ +@@ -658,12 +655,12 @@ transmitter_connect_to_remote(struct weston_transmitter *txr) + remote->display->remote = remote; + /* set connection establish timer */ + loop_est = wl_display_get_event_loop(txr->compositor->wl_display); +- remote->establish_timer = ++ 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 = ++ 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"); +diff --git a/transmitter/plugin.h b/transmitter/plugin.h +index 116c1f6..ec776fa 100644 +--- a/transmitter/plugin.h ++++ b/transmitter/plugin.h +@@ -59,7 +59,7 @@ enum wthp_seat_capability { + }; + + /* epoll structure */ +-struct watch { ++struct watch { + struct waltham_display *display; + int fd; + void (*cb)(struct watch *w, uint32_t events); +@@ -198,9 +198,7 @@ struct weston_transmitter_output { + struct frame *frame; + + struct wl_callback *frame_cb; +- struct wl_listener frame_listener; +- +- bool from_frame_signal; ++ struct renderer *renderer; + }; + + struct weston_transmitter_seat { +diff --git a/transmitter/transmitter_api.h b/transmitter/transmitter_api.h +index 4a660a0..c473256 100644 +--- a/transmitter/transmitter_api.h ++++ b/transmitter/transmitter_api.h +@@ -265,4 +265,13 @@ weston_get_transmitter_ivi_api(struct weston_compositor *compositor) + + /* Remote compositor/output are identified by model */ + ++ ++struct renderer { ++ void (*repaint_output)(struct weston_output *base); ++ struct gst_recorder *recorder; /* gst-recorder instance */ ++ int32_t dmafd; /* dmafd received from compositor-drm */ ++ int surface_width; ++ int surface_height; ++}; ++ + #endif /* WESTON_TRANSMITTER_API_H */ +diff --git a/transmitter/waltham-renderer.c b/transmitter/waltham-renderer.c +new file mode 100644 +index 0000000..f9e4e21 +--- /dev/null ++++ b/transmitter/waltham-renderer.c +@@ -0,0 +1,166 @@ ++/* ++ * 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 ++#include ++#include ++ ++#include "compositor.h" ++#include "libweston/gst-recorder.h" ++ ++#include "transmitter_api.h" ++#include "waltham-renderer.h" ++#include "plugin.h" ++ ++struct waltham_renderer { ++ struct renderer base; ++}; ++ ++static void ++recorder_frame_notify(struct weston_transmitter_output* output) ++{ ++ gst_recorder_frame_dmafd(output->renderer->recorder, output->renderer->dmafd, ++ output->renderer->surface_width*4); ++} ++ ++static int parse_crop_rect(const char *s, struct v4l2_rect* crop) ++{ ++ crop->left = 0; ++ crop->top = 0; ++ crop->width = 0; ++ crop->height = 0; ++ ++ if (sscanf(s, "%dx%d@%dx%d", ++ &crop->width, ++ &crop->height, ++ &crop->top, ++ &crop->left) != 4) ++ return -1; ++ ++ return 0; ++} ++ ++static int ++recorder_enable(struct weston_transmitter_output *output) ++{ ++ int enable_recorder = 0; ++ struct gst_recorder_settings *settings; ++ struct weston_config_section *section; ++ ++ 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; ++ char *crop_params = "384x368@0x0"; ++ ++ struct v4l2_rect crop = { .width = output->base.current_mode->width, ++ .height = output->base.current_mode->height, ++ .top = 0, ++ .left = 0 }; ++ ++ if (output->renderer->recorder) ++ return -1; ++ ++ settings = malloc(sizeof(* settings)); ++ settings->ip = remote->addr; ++ ++ settings->port = atoi(remote->port); ++ ++ settings->bitrate = bitrate; ++ settings->width = output->base.current_mode->width; ++ settings->height = output->base.current_mode->height; ++ ++ settings->crop = crop; ++ ++ if (parse_crop_rect(crop_params, &settings->crop)) { ++ weston_log("[gst recorder] %s:" ++ " failed to parse crop parameter\n", ++ output->base.name); ++ goto err; ++ } ++ ++ 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("crop = %d x %d \n",settings->crop.width,settings->crop.height); ++ weston_log("width = %d \n",settings->width); ++ weston_log("width = %d \n",settings->height); ++ ++ ++ gst_recorder_init(); ++ ++ output->renderer->recorder = ++ gst_recorder_create(settings); ++ if (!output->renderer->recorder) { ++ weston_log("[gst recorder] %s:" ++ " failed to create gst recorder\n", ++ output->base.name); ++ goto err; ++ } ++ ++ weston_log("[gst recorder] %s:" ++ " recorder initialized\n", ++ output->base.name); ++ ++ 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) ++{ ++ recorder_frame_notify(output); ++} ++ ++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; ++ ++ recorder_enable(&output->base); ++ return 0; ++} ++ ++WL_EXPORT struct waltham_renderer_interface waltham_renderer_interface = { ++ .display_create = waltham_renderer_display_create ++}; +diff --git a/transmitter/waltham-renderer.h b/transmitter/waltham-renderer.h +new file mode 100644 +index 0000000..458794e +--- /dev/null ++++ b/transmitter/waltham-renderer.h +@@ -0,0 +1,33 @@ ++/* ++ * 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); ++}; ++ ++#endif /* TRANSMITTER_WALTHAM_RENDERER_H_ */ +-- +2.7.4 + diff --git a/meta-agl-profile-graphical/recipes-graphics/wayland/weston_2.0.0.bbappend b/meta-agl-profile-graphical/recipes-graphics/wayland/weston_2.0.0.bbappend index f6f88a6d6..f23f5e2fa 100644 --- a/meta-agl-profile-graphical/recipes-graphics/wayland/weston_2.0.0.bbappend +++ b/meta-agl-profile-graphical/recipes-graphics/wayland/weston_2.0.0.bbappend @@ -18,6 +18,19 @@ SRC_URI_append = "\ file://0014-simple-shm-remove-ivi-application-support.patch \ file://0015-window-client-remove-ivi-application-support.patch \ file://0016-ivi-shell_add_screen_remove_layer_api.patch \ + file://0017-transmitter-add-an-incomplete-plugin-output-and-poin.patch \ + file://0018-ivi-layout-Register-ivi-layout-interface-It-enables-.patch \ + file://0019-transmitter-transmitter-plugin-for-waltham-protocol.patch \ + file://0020-compositor-add-output-type-to-weston_output.patch \ + file://0021-transmitter-add-output-type-for-waltham-output.patch \ + file://0022-transmitter-did-code-cleaning.patch \ + file://0023-compositor-drm-introduce-drm_get_dmafd_from_view.patch \ + file://0024-transmitter-introduce-waltham-renderer.patch \ " -EXTRA_OECONF_append = " --enable-sys-uid" +DEPENDS += "waltham" + +EXTRA_OECONF_append = " --enable-sys-uid \ + --enable-surface-remoting \ + " +