diff options
Diffstat (limited to 'transmitter-plugin/plugin.c')
-rw-r--r-- | transmitter-plugin/plugin.c | 1024 |
1 files changed, 1024 insertions, 0 deletions
diff --git a/transmitter-plugin/plugin.c b/transmitter-plugin/plugin.c new file mode 100644 index 0000000..2fb60b6 --- /dev/null +++ b/transmitter-plugin/plugin.c @@ -0,0 +1,1024 @@ +/* + * Copyright (C) 2017 Advanced Driver Information Technology Joint Venture GmbH + * Copyright © 2020 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <linux/input.h> + +#include <libweston/libweston.h> +#include <libweston/plugin-registry.h> + +#include <weston.h> +#include <ivi-layout-export.h> + +#include "plugin.h" +#include "transmitter_api.h" + +/* waltham */ +#include <errno.h> +#include <sys/epoll.h> +#include <sys/timerfd.h> +#include <waltham-object.h> +#include <waltham-client.h> +#include <waltham-connection.h> + +#define MAX_EPOLL_WATCHES 2 +#define ESTABLISH_CONNECTION_PERIOD 2000 +#define RETRY_CONNECTION_PERIOD 5000 + +static const struct wthp_seat_listener seat_listener = { + seat_capabilities, + NULL +}; + +/* XXX: all functions and variables with a name, and things marked with a + * comment, containing the word "fake" are mockups that need to be + * removed from the final implementation. + */ + +/** Send configure event through ivi-shell. + * + * \param txs The Transmitter surface. + * \param width Suggestion for surface width. + * \param height Suggestion for surface height. + * + * When the networking code receives a ivi_surface.configure event, it calls + * this function to relay it to the application. + * + * \c txs cannot be a zombie, because transmitter_surface_zombify() must + * tear down the network link, so a zombie cannot receive events. + */ +void +transmitter_surface_ivi_resize(struct weston_transmitter_surface *txs, + int32_t width, int32_t height) +{ + assert(txs->resize_handler); + if (!txs->resize_handler) + return; + + assert(txs->surface); + if (!txs->surface) + return; + + txs->resize_handler(txs->resize_handler_data, width, height); +} + +static void +transmitter_surface_configure(struct weston_transmitter_surface *txs, + int32_t dx, int32_t dy) +{ + assert(txs->surface); + if (!txs->surface) + return; + + txs->attach_dx += dx; + txs->attach_dy += dy; +} + +static void +buffer_send_complete(struct wthp_buffer *b, uint32_t serial) +{ + if (b) + wthp_buffer_destroy(b); +} + +static const struct wthp_buffer_listener buffer_listener = { + buffer_send_complete +}; + +/* + * FIXME: note, at this point, no one is using this. + */ +static void +transmitter_surface_gather_state(struct weston_transmitter_surface *txs) +{ + struct weston_transmitter_remote *remote = txs->remote; + struct waltham_display *dpy = remote->display; + + if (!dpy->running) { + weston_log("transmitter_surface_gather_state() -- dpy not running\n"); + if (remote->status != WESTON_TRANSMITTER_CONNECTION_DISCONNECTED) { + weston_log("transmitter_surface_gather_state() -- disconnected\n"); + + remote->status = + WESTON_TRANSMITTER_CONNECTION_DISCONNECTED; + + wth_connection_destroy(remote->display->connection); + wl_event_source_remove(remote->source); + wl_event_source_timer_update(remote->retry_timer, 1); + } + } else { + /* TODO: transmit surface state to remote */ + /* The buffer must be transmitted to remote side */ + + /* waltham */ + struct weston_surface *surf = txs->surface; + struct weston_compositor *comp = surf->compositor; + int32_t stride, data_sz, width, height; + void *data; + + width = 1; + height = 1; + stride = width * (PIXMAN_FORMAT_BPP(comp->read_format) / 8); + + data = zalloc(stride * height); + data_sz = stride * height; + + /* fake sending buffer */ + txs->wthp_buf = wthp_blob_factory_create_buffer(remote->display->blob_factory, + data_sz, data, surf->width, + surf->height, stride, + PIXMAN_FORMAT_BPP(comp->read_format)); + + wthp_buffer_set_listener(txs->wthp_buf, &buffer_listener, txs); + + wthp_surface_attach(txs->wthp_surf, txs->wthp_buf, + txs->attach_dx, txs->attach_dy); + wthp_surface_damage(txs->wthp_surf, txs->attach_dx, + txs->attach_dy, surf->width, surf->height); + wthp_surface_commit(txs->wthp_surf); + + wth_connection_flush(remote->display->connection); + free(data); + data = NULL; + txs->attach_dx = 0; + txs->attach_dy = 0; + } +} + +/** Mark the weston_transmitter_surface dead. + * + * Stop all remoting actions on this surface. + * + * Still keeps the pointer stored by a shell valid, so it can be freed later. + */ +static void +transmitter_surface_zombify(struct weston_transmitter_surface *txs) +{ + struct weston_transmitter_remote *remote; + /* may be called multiple times */ + if (!txs->surface) + return; + + wl_signal_emit(&txs->destroy_signal, txs); + + wl_list_remove(&txs->surface_destroy_listener.link); + txs->surface = NULL; + + wl_list_remove(&txs->sync_output_destroy_listener.link); + + remote = txs->remote; + + if (!remote->display->compositor) + weston_log("remote->compositor is NULL\n"); + + if (txs->wthp_surf) + wthp_surface_destroy(txs->wthp_surf); + + if (txs->wthp_ivi_surface) + wthp_ivi_surface_destroy(txs->wthp_ivi_surface); + + /* In case called from destroy_transmitter() */ + txs->remote = NULL; +} + +static void +transmitter_surface_destroy(struct weston_transmitter_surface *txs) +{ + transmitter_surface_zombify(txs); + + wl_list_remove(&txs->link); + free(txs); +} + +/** weston_surface destroy signal handler */ +static void +transmitter_surface_destroyed(struct wl_listener *listener, void *data) +{ + struct weston_transmitter_surface *txs = + wl_container_of(listener, txs, surface_destroy_listener); + + assert(data == txs->surface); + + transmitter_surface_zombify(txs); +} + +void +sync_output_destroy_handler(struct wl_listener *listener, void *data) +{ + struct weston_transmitter_surface *txs; + + txs = wl_container_of(listener, txs, sync_output_destroy_listener); + + wl_list_remove(&txs->sync_output_destroy_listener.link); + wl_list_init(&txs->sync_output_destroy_listener.link); + + //weston_surface_force_output(txs->surface, NULL); + weston_surface_unmap(txs->surface); +} + +static void +transmitter_surface_set_ivi_id(struct weston_transmitter_surface *txs, + const char *app_id) +{ + struct weston_transmitter_remote *remote = txs->remote; + struct waltham_display *dpy = remote->display; + + assert(txs->surface); + + if (!dpy) + return; + + if (!dpy->compositor) + return; + + + if (!dpy->seat) + return; + + if (!dpy->application_id) + return; + + txs->wthp_ivi_surface = + wthp_ivi_app_id_surface_create(dpy->application_id, app_id, txs->wthp_surf); + + wth_connection_flush(remote->display->connection); + if (!txs->wthp_ivi_surface) { + weston_log("Failed to create txs->ivi_surf\n"); + return; + } + + weston_log("Created wthp_ivi_surface %p\n", txs->wthp_ivi_surface); +} + +static struct weston_transmitter_surface * +transmitter_surface_push_to_remote(struct weston_surface *ws, const char *app_id, + struct weston_transmitter_remote *remote, + struct wl_listener *stream_status) +{ + struct weston_transmitter *txr = remote->transmitter; + struct weston_transmitter_surface *txs; + bool found = false; + + if (remote->status != WESTON_TRANSMITTER_CONNECTION_READY) { + return NULL; + } + + wl_list_for_each(txs, &remote->surface_list, link) { + if (txs->surface == ws) { + found = true; + break; + } + } + + if (!found) { + txs = NULL; + txs = zalloc(sizeof(*txs)); + + if (!txs) { + weston_log("No memory to create weston_transmitter_surface\n"); + return NULL; + } + + txs->remote = remote; + wl_signal_init(&txs->destroy_signal); + wl_list_insert(&remote->surface_list, &txs->link); + + txs->status = WESTON_TRANSMITTER_STREAM_INITIALIZING; + wl_signal_init(&txs->stream_status_signal); + if (stream_status) + wl_signal_add(&txs->stream_status_signal, stream_status); + + txs->surface = ws; + txs->surface_destroy_listener.notify = transmitter_surface_destroyed; + wl_signal_add(&ws->destroy_signal, &txs->surface_destroy_listener); + + wl_list_init(&txs->sync_output_destroy_listener.link); + + wl_list_init(&txs->frame_callback_list); + wl_list_init(&txs->feedback_list); + + txs->lyt = weston_plugin_api_get(txr->compositor, + IVI_LAYOUT_API_NAME, sizeof(txs->lyt)); + } + + /* TODO: create the content stream connection... */ + if (!remote->display->compositor) + weston_log("remote->compositor is NULL\n"); + + if (!txs->wthp_surf) { + txs->wthp_surf = wthp_compositor_create_surface(remote->display->compositor); + wth_connection_flush(remote->display->connection); + + transmitter_surface_set_ivi_id(txs, app_id); + } + + return txs; +} + +static enum weston_transmitter_stream_status +transmitter_surface_get_stream_status(struct weston_transmitter_surface *txs) +{ + return txs->status; +} + +/* waltham */ + +/* The server advertises a global interface. We can store the ad for later + * and/or bind to it immediately if we want to. We also need to keep track of + * the globals we bind to, so that global_remove can be handled properly (not + * implemented). + */ +static void +registry_handle_global(struct wthp_registry *registry, + uint32_t name, + const char *interface, + uint32_t version) +{ + struct waltham_display *dpy = wth_object_get_user_data((struct wth_object *)registry); + + if (strcmp(interface, "wthp_compositor") == 0) { + assert(!dpy->compositor); + dpy->compositor = (struct wthp_compositor *) + wthp_registry_bind(registry, name, interface, 1); + /* has no events to handle */ + } else if (strcmp(interface, "wthp_blob_factory") == 0) { + assert(!dpy->blob_factory); + dpy->blob_factory = (struct wthp_blob_factory *) + wthp_registry_bind(registry, name, interface, 1); + /* has no events to handle */ + } else if (strcmp(interface, "wthp_seat") == 0) { + assert(!dpy->seat); + dpy->seat = (struct wthp_seat *) + wthp_registry_bind(registry, name, interface, 1); + wthp_seat_set_listener(dpy->seat, &seat_listener, dpy); + } else if (strcmp(interface, "wthp_ivi_application") == 0) { + assert(!dpy->application); + dpy->application = (struct wthp_ivi_application *) + wthp_registry_bind(registry, name, interface, 1); + } else if (strcmp(interface, "wthp_ivi_app_id") == 0) { + assert(!dpy->application_id); + dpy->application_id = (struct wthp_ivi_app_id *) + wthp_registry_bind(registry, name, interface, 1); + } +} + +/* notify connection ready */ +static void +conn_ready_notify(struct wl_listener *l, void *data) +{ + struct weston_transmitter_remote *remote = + wl_container_of(l, remote, establish_listener); + + weston_log("conn_ready_notify()\n"); + + /* Outputs and seats are dynamic, do not guarantee they are all + * present when signalling connection status. + */ + transmitter_remote_create_output_with_name(remote, strdup(remote->model)); + transmitter_remote_create_seat(remote); +} + +/* waltham */ +/* The server removed a global. + * We should destroy everything we created through that global, + * and destroy the objects we created by binding to it. + * The identification happens by global's name, so we need to keep + * track what names we bound. + * (not implemented) + */ +static void +registry_handle_global_remove(struct wthp_registry *wthp_registry, + uint32_t name) +{ + if (wthp_registry) + wthp_registry_free(wthp_registry); +} + +static const struct wthp_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static void +connection_handle_data(struct watch *w, uint32_t events) +{ + struct waltham_display *dpy = wl_container_of(w, dpy, conn_watch); + struct weston_transmitter_remote *remote = dpy->remote; + int ret; + + + if (!dpy->running) { + weston_log("This server is not running yet. %s:%s\n", remote->addr, remote->port); + return; + } + + if (events & EPOLLERR) { + weston_log("Connection errored out.\n"); + dpy->running = false; + remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; + return; + } + + if (events & EPOLLOUT) { + /* Flush out again. If the flush completes, stop + * polling for writable as everything has been written. + */ + ret = wth_connection_flush(dpy->connection); + } + + if (events & EPOLLIN) { + /* Do not ignore EPROTO */ + ret = wth_connection_read(dpy->connection); + + if (ret < 0) { + weston_log("Connection read error %s:%s\n", remote->addr, remote->port); + perror("Connection read error\n"); + dpy->running = false; + remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; + perror("EPOLL_CTL_DEL\n"); + return; + } + } + + if (events & EPOLLHUP) { + weston_log("Connection hung up.\n"); + dpy->running = false; + remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; + + return; + } +} + +static int +waltham_mainloop(int fd, uint32_t mask, void *data) +{ + struct weston_transmitter_remote *remote = data; + struct watch *w; + int ret; + int running_display; + running_display = 0; + + struct waltham_display *dpy = remote->display; + w = &dpy->conn_watch; + if (!dpy) + return -1; + + if (!dpy->connection) + dpy->running = false; + + if (!dpy->running) + return -1; + + running_display++; + /* Dispatch queued events. */ + ret = wth_connection_dispatch(dpy->connection); + if (ret < 0) { + dpy->running = false; + remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; + } + + if (!dpy->running) + return -1; + + /* Run any application idle tasks at this point. */ + /* (nothing to run so far) */ + + /* Flush out buffered requests. If the Waltham socket is + * full, poll it for writable too, and continue flushing then. + */ + ret = wth_connection_flush(dpy->connection); + + if (0 < running_display) { + /* Waltham events only read in the callback, not dispatched, + * if the Waltham socket signalled readable. If it signalled + * writable, flush more. See connection_handle_data(). + */ + w->cb(w, mask); + } + + return 0; +} + +static int +waltham_client_init(struct waltham_display *dpy) +{ + if (!dpy) + return -1; + /* + * get server_address from controller (adrress is set to weston.ini) + */ + dpy->connection = wth_connect_to_server(dpy->remote->addr, dpy->remote->port); + if(!dpy->connection) { + return -2; + } + else { + dpy->remote->status = WESTON_TRANSMITTER_CONNECTION_READY; + wl_signal_emit(&dpy->remote->connection_status_signal, dpy->remote); + } + + dpy->conn_watch.display = dpy; + dpy->conn_watch.cb = connection_handle_data; + dpy->conn_watch.fd = wth_connection_get_fd(dpy->connection); + dpy->remote->source = wl_event_loop_add_fd(dpy->remote->transmitter->loop, + dpy->conn_watch.fd, + WL_EVENT_READABLE, + waltham_mainloop, dpy->remote); + + dpy->display = wth_connection_get_display(dpy->connection); + /* wth_display_set_listener() is already done by waltham, as + * all the events are just control messaging. + */ + + /* Create a registry so that we will get advertisements of the + * interfaces implemented by the server. + */ + dpy->registry = wth_display_get_registry(dpy->display); + wthp_registry_set_listener(dpy->registry, ®istry_listener, dpy); + + /* Roundtrip ensures all globals' ads have been received. */ + if (wth_connection_roundtrip(dpy->connection) < 0) { + weston_log("Roundtrip failed.\n"); + return -1; + } + + if (!dpy->compositor) { + weston_log("Did not find wthp_compositor, quitting.\n"); + return -1; + } + + dpy->running = true; + weston_log("waltham_client_init()\n"); + + return 0; +} + +static int +establish_timer_handler(void *data) +{ + struct weston_transmitter_remote *remote = data; + int ret; + + ret = waltham_client_init(remote->display); + if (ret == -2) { + wl_event_source_timer_update(remote->establish_timer, + ESTABLISH_CONNECTION_PERIOD); + return 0; + } + + weston_log("establish_timer_handler()\n"); + + remote->status = WESTON_TRANSMITTER_CONNECTION_READY; + wl_signal_emit(&remote->connection_status_signal, remote); + return 0; +} + +static void +init_globals(struct waltham_display *dpy) +{ + dpy->compositor = NULL; + dpy->blob_factory = NULL; + dpy->seat = NULL; + dpy->application = NULL; + dpy->pointer = NULL; + dpy->keyboard = NULL; + dpy->touch = NULL; +} + +static void +disconnect_surface(struct weston_transmitter_remote *remote) +{ + struct weston_transmitter_surface *txs; + + wl_list_for_each(txs, &remote->surface_list, link) { + free(txs->wthp_ivi_surface); + txs->wthp_ivi_surface = NULL; + free(txs->wthp_surf); + txs->wthp_surf = NULL; + } +} + +static int +retry_timer_handler(void *data) +{ + struct weston_transmitter_remote *remote = data; + struct waltham_display *dpy = remote->display; + + weston_log("retry_timer_handler()\n"); + + if (!dpy->running) { + registry_handle_global_remove(dpy->registry, 1); + init_globals(dpy); + disconnect_surface(remote); + wl_event_source_timer_update(remote->establish_timer, + ESTABLISH_CONNECTION_PERIOD); + return 0; + } else { + wl_event_source_timer_update(remote->retry_timer, + RETRY_CONNECTION_PERIOD); + } + + return 0; +} + +static struct weston_transmitter_remote * +transmitter_connect_to_remote(struct weston_transmitter *txr) +{ + struct weston_transmitter_remote *remote; + struct wl_event_loop *loop_est, *loop_retry; + + wl_list_for_each_reverse(remote, &txr->remote_list, link) { + /* XXX: actually start connecting */ + /* waltham */ + remote->display = zalloc(sizeof *remote->display); + if (!remote->display) { + weston_log("Failed to allocate remote display\n"); + return NULL; + } + + remote->display->remote = remote; + + weston_log("transmitter_connect_to_remote() for remote %p\n", remote); + + /* set connection establish timer */ + loop_est = wl_display_get_event_loop(txr->compositor->wl_display); + remote->establish_timer = + wl_event_loop_add_timer(loop_est, establish_timer_handler, remote); + wl_event_source_timer_update(remote->establish_timer, 1); + + /* set connection retry timer */ + loop_retry = wl_display_get_event_loop(txr->compositor->wl_display); + remote->retry_timer = + wl_event_loop_add_timer(loop_retry, retry_timer_handler, remote); + wl_signal_emit(&remote->conn_establish_signal, NULL); + } + + return remote; +} + +static enum weston_transmitter_connection_status +transmitter_remote_get_status(struct weston_transmitter_remote *remote) +{ + return remote->status; +} + +static void +transmitter_remote_destroy(struct weston_transmitter_remote *remote) +{ + struct weston_transmitter_surface *txs; + struct weston_transmitter_output *output, *otmp; + struct weston_transmitter_seat *seat, *stmp; + + /* Do not emit connection_status_signal. */ + + /* + * Must not touch remote->transmitter as it may be stale: the + * destruction order between the shell and Transmitter is undefined. + */ + + if (!wl_list_empty(&remote->surface_list)) + weston_log("Transmitter warning: surfaces remain in %s.\n", __func__); + + wl_list_for_each(txs, &remote->surface_list, link) + txs->remote = NULL; + + wl_list_remove(&remote->surface_list); + + wl_list_for_each_safe(seat, stmp, &remote->seat_list, link) + transmitter_seat_destroy(seat); + + wl_list_for_each_safe(output, otmp, &remote->output_list, link) + transmitter_output_destroy(output); + + free(remote->addr); + wl_list_remove(&remote->link); + + wl_event_source_remove(remote->source); + + free(remote); +} + +/** Transmitter is destroyed on compositor shutdown. */ +static void +transmitter_compositor_destroyed(struct wl_listener *listener, void *data) +{ + struct weston_transmitter_remote *remote; + struct weston_transmitter_surface *txs; + struct weston_transmitter *txr = + wl_container_of(listener, txr, compositor_destroy_listener); + + assert(data == txr->compositor); + + /* may be called before or after shell cleans up */ + wl_list_for_each(remote, &txr->remote_list, link) { + wl_list_for_each(txs, &remote->surface_list, link) { + transmitter_surface_zombify(txs); + } + } + + /* + * Remove the head in case the list is not empty, to avoid + * transmitter_remote_destroy() accessing freed memory if the shell + * cleans up after Transmitter. + */ + wl_list_remove(&txr->remote_list); + + free(txr); +} + +static struct weston_transmitter * +transmitter_get(struct weston_compositor *compositor) +{ + struct wl_listener *listener; + struct weston_transmitter *txr; + + listener = wl_signal_get(&compositor->destroy_signal, + transmitter_compositor_destroyed); + if (!listener) + return NULL; + + txr = wl_container_of(listener, txr, compositor_destroy_listener); + assert(compositor == txr->compositor); + + return txr; +} + +static void +transmitter_register_connection_status(struct weston_transmitter *txr, + struct wl_listener *connected_listener) +{ + wl_signal_add(&txr->connected_signal, connected_listener); +} + +static struct weston_surface * +transmitter_get_weston_surface(struct weston_transmitter_surface *txs) +{ + return txs->surface; +} + +static struct weston_transmitter_remote * +transmitter_get_transmitter_remote(const char *output_transmitter_name, struct weston_transmitter *transmitter) +{ + + struct weston_transmitter_remote *trans_remote; + + if (!output_transmitter_name) + return NULL; + + wl_list_for_each(trans_remote, &transmitter->remote_list, link) { + struct weston_transmitter_output *trans_output; + wl_list_for_each(trans_output, &trans_remote->output_list, link) { + const char *name = trans_output->base.name; + + if (name && !strcmp(output_transmitter_name, name)) + return trans_remote; + + name = trans_output->name; + if (name && !strcmp(output_transmitter_name, name)) + return trans_remote; + } + } + + return NULL; +} + +static const struct weston_transmitter_api transmitter_api_impl = { + transmitter_get, + transmitter_connect_to_remote, + transmitter_remote_get_status, + transmitter_remote_destroy, + transmitter_surface_push_to_remote, + transmitter_surface_get_stream_status, + transmitter_surface_destroy, + transmitter_surface_configure, + transmitter_surface_gather_state, + transmitter_register_connection_status, + transmitter_get_weston_surface, + transmitter_get_transmitter_remote, +}; + +static void +transmitter_surface_set_resize_callback( + struct weston_transmitter_surface *txs, + weston_transmitter_ivi_resize_handler_t cb, + void *data) +{ + txs->resize_handler = cb; + txs->resize_handler_data = data; +} + +static void +_transmitter_surface_set_ivi_id(struct weston_transmitter_surface *txs, uint32_t ivi_id) +{ + +} + +static const struct weston_transmitter_ivi_api transmitter_ivi_api_impl = { + _transmitter_surface_set_ivi_id, + transmitter_surface_set_resize_callback, +}; + +static int +transmitter_create_remote(struct weston_transmitter *txr, + const char *model, + const char *addr, + const char *port, + const char *width, + const char *height) +{ + struct weston_transmitter_remote *remote; + + remote = zalloc(sizeof (*remote)); + if (!remote) + return -1; + + remote->transmitter = txr; + wl_list_insert(&txr->remote_list, &remote->link); + + remote->model = strdup(model); + remote->addr = strdup(addr); + remote->port = strdup(port); + if (remote->width) + remote->width = atoi(width); + if (remote->height) + remote->height = atoi(height); + remote->status = WESTON_TRANSMITTER_CONNECTION_INITIALIZING; + + weston_log("Creating transmitter remote output model %s, addr %s, " + "port %s, width %d, height %d, status %d\n", + remote->model, remote->addr, remote->port, remote->width, + remote->height, remote->status); + + wl_signal_init(&remote->connection_status_signal); + + wl_list_init(&remote->output_list); + wl_list_init(&remote->surface_list); + wl_list_init(&remote->seat_list); + + wl_signal_init(&remote->conn_establish_signal); + remote->establish_listener.notify = conn_ready_notify; + wl_signal_add(&remote->conn_establish_signal, &remote->establish_listener); + + return 0; +} + +struct wet_compositor { + struct weston_config *config; + struct wet_output_config *parsed_options; + struct wl_listener pending_output_listener; + bool drm_use_current_mode; +}; + +static int +load_config(struct weston_config **config, bool no_config, + const char *config_file) +{ + const char *file = "agl-compositor.ini"; + const char *full_path; + + if (config_file) + file = config_file; + + if (!no_config) + *config = weston_config_parse(file); + + if (*config) { + full_path = weston_config_get_full_path(*config); + + weston_log("Using config file '%s'.\n", full_path); + setenv(WESTON_CONFIG_FILE_ENV_VAR, full_path, 1); + + return 0; + } + + if (config_file && !no_config) { + weston_log("fatal: error opening or reading config file '%s'.\n", + config_file); + + return -1; + } + + weston_log("Starting with no config file.\n"); + setenv(WESTON_CONFIG_FILE_ENV_VAR, "", 1); + + return 0; +} + + +static void +transmitter_get_server_config(struct weston_transmitter *txr) +{ + struct weston_config *config = NULL; + struct weston_config_section *section; + const char *name = NULL; + char *model = NULL; + char *addr = NULL; + char *port = NULL; + char *width = NULL; + char *height = NULL; + int ret; + + /* FIXME: this assume as hard-coded agl-compositor */ + if (load_config(&config, 0, "agl-compositor.ini") < 0) + return; + + section = weston_config_get_section(config, "remote", NULL, NULL); + + while (weston_config_next_section(config, §ion, &name)) { + if (0 == strcmp(name, "transmitter-output")) { + if (0 != weston_config_section_get_string(section, "name", + &model, 0)) + continue; + + if (0 != weston_config_section_get_string(section, "host", + &addr, 0)) + continue; + + if (0 != weston_config_section_get_string(section, "port", + &port, 0)) + continue; + + ret = transmitter_create_remote(txr, model, addr, + port, width, height); + if (ret < 0) { + weston_log("Fatal: Transmitter create_remote failed.\n"); + } + } + } +} + +WL_EXPORT int +wet_module_init(struct weston_compositor *compositor, int *argc, char *argv[]) +{ + struct weston_transmitter *txr; + int ret; + + txr = zalloc(sizeof *txr); + if (!txr){ + weston_log("Transmitter disabled\n"); + return -1; + } + wl_list_init(&txr->remote_list); + + txr->compositor = compositor; + txr->compositor_destroy_listener.notify = + transmitter_compositor_destroyed; + wl_signal_add(&compositor->destroy_signal, + &txr->compositor_destroy_listener); + + ret = weston_plugin_api_register(compositor, + WESTON_TRANSMITTER_API_NAME, + &transmitter_api_impl, + sizeof(transmitter_api_impl)); + if (ret < 0) { + weston_log("Fatal: Transmitter API registration failed.\n"); + goto fail; + } + + ret = weston_plugin_api_register(compositor, + WESTON_TRANSMITTER_IVI_API_NAME, + &transmitter_ivi_api_impl, + sizeof(transmitter_ivi_api_impl)); + if (ret < 0) { + weston_log("Fatal: Transmitter IVI API registration failed.\n"); + goto fail; + } + + weston_log("Transmitter initialized.\n"); + + txr->loop = wl_display_get_event_loop(compositor->wl_display); + transmitter_get_server_config(txr); + transmitter_connect_to_remote(txr); + + return 0; + +fail: + wl_list_remove(&txr->compositor_destroy_listener.link); + free(txr); + + return -1; +} |