From 9e55f4f9c921782263b784e7f6e0e9b0fc9095ca Mon Sep 17 00:00:00 2001 From: Manuel Bachmann Date: Mon, 28 Sep 2015 04:45:19 +0200 Subject: [PATCH] Backport IVI-Shell from Weston 1.9.0 to 1.5.0 IVI-Shell is the alternative Weston shell implementing the eponymous protocol, and supported in client toolkits such as EFL, Qt... We backport only the necessary, without touching the core compositor if possible (was only necessary for surface copying logic which had a patch in Tizen IVI). Signed-off-by: Manuel Bachmann --- Makefile.am | 113 +- clients/ivi-shell-user-interface.c | 1312 ++++++++++++++++ clients/simple-egl.c | 78 +- clients/simple-shm.c | 37 + clients/window.c | 57 +- configure.ac | 9 + data/background.png | Bin 0 -> 245579 bytes data/fullscreen.png | Bin 0 -> 3406 bytes data/home.png | Bin 0 -> 4629 bytes data/icon_ivi_clickdot.png | Bin 0 -> 39523 bytes data/icon_ivi_flower.png | Bin 0 -> 24475 bytes data/icon_ivi_simple-egl.png | Bin 0 -> 29316 bytes data/icon_ivi_simple-shm.png | Bin 0 -> 71120 bytes data/icon_ivi_smoke.png | Bin 0 -> 46577 bytes data/panel.png | Bin 0 -> 41955 bytes data/random.png | Bin 0 -> 4891 bytes data/sidebyside.png | Bin 0 -> 3929 bytes data/tiling.png | Bin 0 -> 5620 bytes ivi-shell/hmi-controller.c | 1814 ++++++++++++++++++++++ ivi-shell/input-panel-ivi.c | 397 +++++ ivi-shell/ivi-layout-export.h | 813 ++++++++++ ivi-shell/ivi-layout-private.h | 229 +++ ivi-shell/ivi-layout-transition.c | 871 +++++++++++ ivi-shell/ivi-layout.c | 3011 ++++++++++++++++++++++++++++++++++++ ivi-shell/ivi-shell.c | 469 ++++++ ivi-shell/ivi-shell.h | 67 + ivi-shell/weston.ini.in | 98 ++ protocol/ivi-application.xml | 100 ++ protocol/ivi-hmi-controller.xml | 98 ++ shared/helpers.h | 96 ++ src/compositor.c | 48 + src/compositor.h | 20 + src/gl-renderer.c | 150 ++ src/pixman-renderer.c | 51 + 34 files changed, 9915 insertions(+), 23 deletions(-) create mode 100644 clients/ivi-shell-user-interface.c create mode 100644 data/background.png create mode 100644 data/fullscreen.png create mode 100644 data/home.png create mode 100644 data/icon_ivi_clickdot.png create mode 100644 data/icon_ivi_flower.png create mode 100644 data/icon_ivi_simple-egl.png create mode 100644 data/icon_ivi_simple-shm.png create mode 100644 data/icon_ivi_smoke.png create mode 100644 data/panel.png create mode 100644 data/random.png create mode 100644 data/sidebyside.png create mode 100644 data/tiling.png create mode 100644 ivi-shell/hmi-controller.c create mode 100644 ivi-shell/input-panel-ivi.c create mode 100644 ivi-shell/ivi-layout-export.h create mode 100644 ivi-shell/ivi-layout-private.h create mode 100644 ivi-shell/ivi-layout-transition.c create mode 100644 ivi-shell/ivi-layout.c create mode 100644 ivi-shell/ivi-shell.c create mode 100644 ivi-shell/ivi-shell.h create mode 100644 ivi-shell/weston.ini.in create mode 100644 protocol/ivi-application.xml create mode 100644 protocol/ivi-hmi-controller.xml create mode 100644 shared/helpers.h diff --git a/Makefile.am b/Makefile.am index 343adc6..7649d7d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,7 +8,7 @@ BUILT_SOURCES = DISTCHECK_CONFIGURE_FLAGS = --disable-setuid-install -EXTRA_DIST = weston.ini.in +EXTRA_DIST = weston.ini.in ivi-shell/weston.ini.in weston.ini : $(srcdir)/weston.ini.in $(AM_V_GEN)$(SED) \ @@ -17,7 +17,16 @@ weston.ini : $(srcdir)/weston.ini.in -e 's|@libexecdir[@]|$(libexecdir)|g' \ $< > $@ -all-local : weston.ini +ivi-shell/weston.ini : $(srcdir)/ivi-shell/weston.ini.in + $(AM_V_GEN)$(SED) \ + -e 's|@bindir[@]|$(bindir)|g' \ + -e 's|@abs_top_builddir[@]|$(abs_top_builddir)|g' \ + -e 's|@abs_top_srcdir[@]|$(abs_top_srcdir)|g' \ + -e 's|@libexecdir[@]|$(libexecdir)|g' \ + -e 's|@plugin_prefix[@]||g' \ + $< > $@ + +all-local : weston.ini ivi-shell/weston.ini AM_CFLAGS = $(GCC_CFLAGS) @@ -33,7 +42,7 @@ AM_CPPFLAGS = \ -DLIBEXECDIR='"$(libexecdir)"' \ -DBINDIR='"$(bindir)"' -CLEANFILES = weston.ini $(BUILT_SOURCES) +CLEANFILES = weston.ini ivi-shell/weston.ini $(BUILT_SOURCES) bin_PROGRAMS += weston @@ -361,6 +370,11 @@ libexec_PROGRAMS += \ weston-keyboard \ weston-simple-im +if ENABLE_IVI_SHELL +libexec_PROGRAMS += \ + weston-ivi-shell-user-interface +endif + demo_clients = \ weston-flower \ weston-image \ @@ -394,7 +408,9 @@ nodist_weston_simple_shm_SOURCES = \ protocol/xdg-shell-protocol.c \ protocol/xdg-shell-client-protocol.h \ protocol/fullscreen-shell-protocol.c \ - protocol/fullscreen-shell-client-protocol.h + protocol/fullscreen-shell-client-protocol.h \ + protocol/ivi-application-protocol.c \ + protocol/ivi-application-client-protocol.h weston_simple_shm_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS) weston_simple_shm_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la @@ -412,7 +428,9 @@ demo_clients += weston-simple-egl weston_simple_egl_SOURCES = clients/simple-egl.c nodist_weston_simple_egl_SOURCES = \ protocol/xdg-shell-protocol.c \ - protocol/xdg-shell-client-protocol.h + protocol/xdg-shell-client-protocol.h \ + protocol/ivi-application-protocol.c \ + protocol/ivi-application-client-protocol.h weston_simple_egl_CFLAGS = $(AM_CFLAGS) $(SIMPLE_EGL_CLIENT_CFLAGS) weston_simple_egl_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm endif @@ -431,7 +449,9 @@ nodist_libtoytoolkit_la_SOURCES = \ protocol/workspaces-protocol.c \ protocol/workspaces-client-protocol.h \ protocol/xdg-shell-protocol.c \ - protocol/xdg-shell-client-protocol.h + protocol/xdg-shell-client-protocol.h \ + protocol/ivi-application-protocol.c \ + protocol/ivi-application-client-protocol.h BUILT_SOURCES += $(nodist_libtoytoolkit_la_SOURCES) @@ -570,6 +590,19 @@ nodist_weston_desktop_shell_SOURCES = \ weston_desktop_shell_LDADD = libtoytoolkit.la weston_desktop_shell_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) +if ENABLE_IVI_SHELL +weston_ivi_shell_user_interface_SOURCES = \ + clients/ivi-shell-user-interface.c \ + shared/helpers.h +nodist_weston_ivi_shell_user_interface_SOURCES = \ + protocol/ivi-hmi-controller-client-protocol.h \ + protocol/ivi-hmi-controller-protocol.c \ + protocol/ivi-application-client-protocol.h \ + protocol/ivi-application-protocol.c +weston_ivi_shell_user_interface_LDADD = libtoytoolkit.la +weston_ivi_shell_user_interface_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) +endif + if BUILD_FULL_GL_CLIENTS demo_clients += weston-gears weston_gears_SOURCES = clients/gears.c @@ -616,8 +649,11 @@ BUILT_SOURCES += \ protocol/fullscreen-shell-protocol.c \ protocol/fullscreen-shell-client-protocol.h \ protocol/xdg-shell-protocol.c \ - protocol/xdg-shell-client-protocol.h - + protocol/xdg-shell-client-protocol.h \ + protocol/ivi-hmi-controller-protocol.c \ + protocol/ivi-hmi-controller-client-protocol.h \ + protocol/ivi-application-protocol.c \ + protocol/ivi-application-client-protocol.h westondatadir = $(datadir)/weston dist_westondata_DATA = \ @@ -631,6 +667,21 @@ dist_westondata_DATA = \ data/sign_maximize.png \ data/sign_minimize.png +if ENABLE_IVI_SHELL +dist_westondata_DATA += \ + data/background.png \ + data/tiling.png \ + data/fullscreen.png \ + data/panel.png \ + data/random.png \ + data/sidebyside.png \ + data/home.png \ + data/icon_ivi_clickdot.png \ + data/icon_ivi_flower.png \ + data/icon_ivi_simple-egl.png \ + data/icon_ivi_simple-shm.png \ + data/icon_ivi_smoke.png +endif if BUILD_WCAP_TOOLS bin_PROGRAMS += wcap-decode @@ -700,6 +751,48 @@ nodist_fullscreen_shell_la_SOURCES = \ BUILT_SOURCES += $(nodist_fullscreen_shell_la_SOURCES) endif +if ENABLE_IVI_SHELL + +module_LTLIBRARIES += \ + $(ivi_shell) \ + $(hmi_controller) + +ivi_shell = ivi-shell.la +ivi_shell_la_LDFLAGS = -module -avoid-version +ivi_shell_la_LIBADD = $(COMPOSITOR_LIBS) libshared.la +ivi_shell_la_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS) +ivi_shell_la_SOURCES = \ + ivi-shell/ivi-layout-export.h \ + ivi-shell/ivi-layout-private.h \ + ivi-shell/ivi-layout.c \ + ivi-shell/ivi-layout-transition.c \ + ivi-shell/ivi-shell.h \ + ivi-shell/ivi-shell.c \ + ivi-shell/input-panel-ivi.c \ + shared/helpers.h +nodist_ivi_shell_la_SOURCES = \ + protocol/ivi-application-protocol.c \ + protocol/ivi-application-server-protocol.h + +BUILT_SOURCES += $(nodist_ivi_shell_la_SOURCES) + +hmi_controller = hmi-controller.la +hmi_controller_la_LDFLAGS = -module -avoid-version +hmi_controller_la_LIBADD = $(COMPOSITOR_LIBS) libshared.la +hmi_controller_la_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS) +hmi_controller_la_SOURCES = \ + ivi-shell/ivi-layout-export.h \ + ivi-shell/hmi-controller.c \ + shared/helpers.h +nodist_hmi_controller_la_SOURCES = \ + protocol/ivi-hmi-controller-protocol.c \ + protocol/ivi-hmi-controller-server-protocol.h + +BUILT_SOURCES += $(nodist_hmi_controller_la_SOURCES) + +endif + + if ENABLE_SCREEN_SHARING module_LTLIBRARIES += screen-share.la @@ -969,7 +1062,9 @@ EXTRA_DIST += \ protocol/wayland-test.xml \ protocol/xdg-shell.xml \ protocol/fullscreen-shell.xml \ - protocol/scaler.xml + protocol/scaler.xml \ + protocol/ivi-application.xml \ + protocol/ivi-hmi-controller.xml man_MANS = weston.1 weston.ini.5 diff --git a/clients/ivi-shell-user-interface.c b/clients/ivi-shell-user-interface.c new file mode 100644 index 0000000..dbe7a88 --- /dev/null +++ b/clients/ivi-shell-user-interface.c @@ -0,0 +1,1312 @@ +/* + * Copyright (C) 2013 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "shared/cairo-util.h" +#include "shared/config-parser.h" +#include "shared/helpers.h" +#include "shared/os-compatibility.h" +#include "ivi-application-client-protocol.h" +#include "ivi-hmi-controller-client-protocol.h" + +/** + * A reference implementation how to use ivi-hmi-controller interface to + * interact with hmi-controller. This is launched from hmi-controller by using + * hmi_client_start and create a pthread. + * + * The basic flow is as followed, + * 1/ read configuration from weston.ini. + * 2/ draw png file to surface according to configuration of weston.ini + * 3/ set up UI by using ivi-hmi-controller protocol + * 4/ Enter event loop + * 5/ If a surface receives touch/pointer event, followings are invoked + * according to type of event and surface + * 5-1/ If a surface to launch ivi_application receive touch up, it execs + * ivi-application configured in weston.ini. + * 5-2/ If a surface to switch layout mode receive touch up, it sends a request, + * ivi_hmi_controller_switch_mode, to hmi-controller. + * 5-3/ If a surface to show workspace having launchers, it sends a request, + * ivi_hmi_controller_home, to hmi-controller. + * 5-4/ If touch down events happens in workspace, + * ivi_hmi_controller_workspace_control is sent to slide workspace. + * When control finished, event: ivi_hmi_controller_workspace_end_control + * is received. + */ + +/***************************************************************************** + * structure, globals + ****************************************************************************/ +enum cursor_type { + CURSOR_BOTTOM_LEFT, + CURSOR_BOTTOM_RIGHT, + CURSOR_BOTTOM, + CURSOR_DRAGGING, + CURSOR_LEFT_PTR, + CURSOR_LEFT, + CURSOR_RIGHT, + CURSOR_TOP_LEFT, + CURSOR_TOP_RIGHT, + CURSOR_TOP, + CURSOR_IBEAM, + CURSOR_HAND1, + CURSOR_WATCH, + + CURSOR_BLANK +}; +struct wlContextCommon { + struct wl_display *wlDisplay; + struct wl_registry *wlRegistry; + struct wl_compositor *wlCompositor; + struct wl_shm *wlShm; + uint32_t formats; + struct wl_seat *wlSeat; + struct wl_pointer *wlPointer; + struct wl_touch *wlTouch; + struct ivi_application *iviApplication; + struct ivi_hmi_controller *hmiCtrl; + struct hmi_homescreen_setting *hmi_setting; + struct wl_list list_wlContextStruct; + struct wl_surface *enterSurface; + int32_t is_home_on; + struct wl_cursor_theme *cursor_theme; + struct wl_cursor **cursors; + struct wl_surface *pointer_surface; + enum cursor_type current_cursor; + uint32_t enter_serial; +}; + +struct wlContextStruct { + struct wlContextCommon *cmm; + struct wl_surface *wlSurface; + struct wl_buffer *wlBuffer; + cairo_surface_t *ctx_image; + void *data; + uint32_t id_surface; + struct wl_list link; +}; + +struct +hmi_homescreen_srf { + uint32_t id; + char *filePath; + uint32_t color; +}; + +struct +hmi_homescreen_workspace { + struct wl_array launcher_id_array; + struct wl_list link; +}; + +struct +hmi_homescreen_launcher { + uint32_t icon_surface_id; + uint32_t workspace_id; + char *icon; + char *path; + struct wl_list link; +}; + +struct +hmi_homescreen_setting { + struct hmi_homescreen_srf background; + struct hmi_homescreen_srf panel; + struct hmi_homescreen_srf tiling; + struct hmi_homescreen_srf sidebyside; + struct hmi_homescreen_srf fullscreen; + struct hmi_homescreen_srf random; + struct hmi_homescreen_srf home; + struct hmi_homescreen_srf workspace_background; + + struct wl_list workspace_list; + struct wl_list launcher_list; + + char *cursor_theme; + int32_t cursor_size; + uint32_t transition_duration; +}; + +static void * +fail_on_null(void *p, size_t size, char *file, int32_t line) +{ + if (size && !p) { + fprintf(stderr, "%s(%d) %zd: out of memory\n", + file, line, size); + exit(EXIT_FAILURE); + } + + return p; +} + +static void * +mem_alloc(size_t size, char *file, int32_t line) +{ + return fail_on_null(calloc(1, size), size, file, line); +} + +#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__) + +/***************************************************************************** + * Event Handler + ****************************************************************************/ + +static void +shm_format(void *data, struct wl_shm *pWlShm, uint32_t format) +{ + struct wlContextCommon *pCtx = data; + + pCtx->formats |= (1 << format); +} + +static struct wl_shm_listener shm_listenter = { + shm_format +}; + +static int32_t +getIdOfWlSurface(struct wlContextCommon *pCtx, struct wl_surface *wlSurface) +{ + struct wlContextStruct *pWlCtxSt = NULL; + + if (NULL == pCtx || NULL == wlSurface ) + return 0; + + wl_list_for_each(pWlCtxSt, &pCtx->list_wlContextStruct, link) { + if (pWlCtxSt->wlSurface == wlSurface) + return pWlCtxSt->id_surface; + } + + return -1; +} + +static void +set_pointer_image(struct wlContextCommon *pCtx, uint32_t index) +{ + struct wl_cursor *cursor = NULL; + struct wl_cursor_image *image = NULL; + struct wl_buffer *buffer = NULL; + + if (!pCtx->wlPointer || !pCtx->cursors) + return; + + if (CURSOR_BLANK == pCtx->current_cursor) { + wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial, + NULL, 0, 0); + return; + } + + cursor = pCtx->cursors[pCtx->current_cursor]; + if (!cursor) + return; + + if (cursor->image_count <= index) { + fprintf(stderr, "cursor index out of range\n"); + return; + } + + image = cursor->images[index]; + buffer = wl_cursor_image_get_buffer(image); + + if (!buffer) + return; + + wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial, + pCtx->pointer_surface, + image->hotspot_x, image->hotspot_y); + + wl_surface_attach(pCtx->pointer_surface, buffer, 0, 0); + + wl_surface_damage(pCtx->pointer_surface, 0, 0, + image->width, image->height); + + wl_surface_commit(pCtx->pointer_surface); +} + +static void +PointerHandleEnter(void *data, struct wl_pointer *wlPointer, uint32_t serial, + struct wl_surface *wlSurface, wl_fixed_t sx, wl_fixed_t sy) +{ + struct wlContextCommon *pCtx = data; + + pCtx->enter_serial = serial; + pCtx->enterSurface = wlSurface; + set_pointer_image(pCtx, 0); +#ifdef _DEBUG + printf("ENTER PointerHandleEnter: x(%d), y(%d)\n", sx, sy); +#endif +} + +static void +PointerHandleLeave(void *data, struct wl_pointer *wlPointer, uint32_t serial, + struct wl_surface *wlSurface) +{ + struct wlContextCommon *pCtx = data; + + pCtx->enterSurface = NULL; + +#ifdef _DEBUG + printf("ENTER PointerHandleLeave: serial(%d)\n", serial); +#endif +} + +static void +PointerHandleMotion(void *data, struct wl_pointer *wlPointer, uint32_t time, + wl_fixed_t sx, wl_fixed_t sy) +{ +#ifdef _DEBUG + printf("ENTER PointerHandleMotion: x(%d), y(%d)\n", sx, sy); +#endif +} + +/** + * if a surface assigned as launcher receives touch-off event, invoking + * ivi-application which configured in weston.ini with path to binary. + */ +extern char **environ; /*defied by libc */ + +static pid_t +execute_process(char *path, char *argv[]) +{ + pid_t pid = fork(); + if (pid < 0) + fprintf(stderr, "Failed to fork\n"); + + if (pid) + return pid; + + if (-1 == execve(path, argv, environ)) { + fprintf(stderr, "Failed to execve %s\n", path); + exit(1); + } + + return pid; +} + +static int32_t +launcher_button(uint32_t surfaceId, struct wl_list *launcher_list) +{ + struct hmi_homescreen_launcher *launcher = NULL; + + wl_list_for_each(launcher, launcher_list, link) { + char *argv[] = { NULL }; + + if (surfaceId != launcher->icon_surface_id) + continue; + + execute_process(launcher->path, argv); + + return 1; + } + + return 0; +} + +/** + * is-method to identify a surface set as launcher in workspace or workspace + * itself. This is-method is used to decide whether request; + * ivi_hmi_controller_workspace_control is sent or not. + */ +static int32_t +isWorkspaceSurface(uint32_t id, struct hmi_homescreen_setting *hmi_setting) +{ + struct hmi_homescreen_launcher *launcher = NULL; + + if (id == hmi_setting->workspace_background.id) + return 1; + + wl_list_for_each(launcher, &hmi_setting->launcher_list, link) { + if (id == launcher->icon_surface_id) + return 1; + } + + return 0; +} + +/** + * Decide which request is sent to hmi-controller + */ +static void +touch_up(struct ivi_hmi_controller *hmi_ctrl, uint32_t id_surface, + int32_t *is_home_on, struct hmi_homescreen_setting *hmi_setting) +{ + if (launcher_button(id_surface, &hmi_setting->launcher_list)) { + *is_home_on = 0; + ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF); + } else if (id_surface == hmi_setting->tiling.id) { + ivi_hmi_controller_switch_mode(hmi_ctrl, + IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING); + } else if (id_surface == hmi_setting->sidebyside.id) { + ivi_hmi_controller_switch_mode(hmi_ctrl, + IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE); + } else if (id_surface == hmi_setting->fullscreen.id) { + ivi_hmi_controller_switch_mode(hmi_ctrl, + IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN); + } else if (id_surface == hmi_setting->random.id) { + ivi_hmi_controller_switch_mode(hmi_ctrl, + IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM); + } else if (id_surface == hmi_setting->home.id) { + *is_home_on = !(*is_home_on); + if (*is_home_on) { + ivi_hmi_controller_home(hmi_ctrl, + IVI_HMI_CONTROLLER_HOME_ON); + } else { + ivi_hmi_controller_home(hmi_ctrl, + IVI_HMI_CONTROLLER_HOME_OFF); + } + } +} + +/** + * Even handler of Pointer event. IVI system is usually manipulated by touch + * screen. However, some systems also have pointer device. + * Release is the same behavior as touch off + * Pressed is the same behavior as touch on + */ +static void +PointerHandleButton(void *data, struct wl_pointer *wlPointer, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state) +{ + struct wlContextCommon *pCtx = data; + struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl; + const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface); + + if (BTN_RIGHT == button) + return; + + switch (state) { + case WL_POINTER_BUTTON_STATE_RELEASED: + touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, + pCtx->hmi_setting); + break; + + case WL_POINTER_BUTTON_STATE_PRESSED: + + if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) { + ivi_hmi_controller_workspace_control(hmi_ctrl, + pCtx->wlSeat, + serial); + } + + break; + } +#ifdef _DEBUG + printf("ENTER PointerHandleButton: button(%d), state(%d)\n", + button, state); +#endif +} + +static void +PointerHandleAxis(void *data, struct wl_pointer *wlPointer, uint32_t time, + uint32_t axis, wl_fixed_t value) +{ +#ifdef _DEBUG + printf("ENTER PointerHandleAxis: axis(%d), value(%d)\n", axis, value); +#endif +} + +static struct wl_pointer_listener pointer_listener = { + PointerHandleEnter, + PointerHandleLeave, + PointerHandleMotion, + PointerHandleButton, + PointerHandleAxis +}; + +/** + * Even handler of touch event + */ +static void +TouchHandleDown(void *data, struct wl_touch *wlTouch, uint32_t serial, + uint32_t time, struct wl_surface *surface, int32_t id, + wl_fixed_t x_w, wl_fixed_t y_w) +{ + struct wlContextCommon *pCtx = data; + struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl; + uint32_t id_surface = 0; + + if (0 == id) + pCtx->enterSurface = surface; + + id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface); + + /** + * When touch down happens on surfaces of workspace, ask + * hmi-controller to start control workspace to select page of + * workspace. After sending seat to hmi-controller by + * ivi_hmi_controller_workspace_control, + * hmi-controller-homescreen doesn't receive any event till + * hmi-controller sends back it. + */ + if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) { + ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, + serial); + } +} + +static void +TouchHandleUp(void *data, struct wl_touch *wlTouch, uint32_t serial, + uint32_t time, int32_t id) +{ + struct wlContextCommon *pCtx = data; + struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl; + + const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface); + + /** + * triggering event according to touch-up happening on which surface. + */ + if (id == 0){ + touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, + pCtx->hmi_setting); + } +} + +static void +TouchHandleMotion(void *data, struct wl_touch *wlTouch, uint32_t time, + int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) +{ +} + +static void +TouchHandleFrame(void *data, struct wl_touch *wlTouch) +{ +} + +static void +TouchHandleCancel(void *data, struct wl_touch *wlTouch) +{ +} + +static struct wl_touch_listener touch_listener = { + TouchHandleDown, + TouchHandleUp, + TouchHandleMotion, + TouchHandleFrame, + TouchHandleCancel, +}; + +/** + * Handler of capabilities + */ +static void +seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t caps) +{ + struct wlContextCommon *p_wlCtx = (struct wlContextCommon*)data; + struct wl_seat *wlSeat = p_wlCtx->wlSeat; + struct wl_pointer *wlPointer = p_wlCtx->wlPointer; + struct wl_touch *wlTouch = p_wlCtx->wlTouch; + + if (p_wlCtx->hmi_setting->cursor_theme) { + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wlPointer){ + wlPointer = wl_seat_get_pointer(wlSeat); + wl_pointer_add_listener(wlPointer, + &pointer_listener, data); + } else + if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wlPointer){ + wl_pointer_destroy(wlPointer); + wlPointer = NULL; + } + p_wlCtx->wlPointer = wlPointer; + } + + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wlTouch){ + wlTouch = wl_seat_get_touch(wlSeat); + wl_touch_add_listener(wlTouch, &touch_listener, data); + } else + if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wlTouch){ + wl_touch_destroy(wlTouch); + wlTouch = NULL; + } + p_wlCtx->wlTouch = wlTouch; +} + +static struct wl_seat_listener seat_Listener = { + seat_handle_capabilities, +}; + +/** + * Registration of event + * This event is received when hmi-controller server finished controlling + * workspace. + */ +static void +ivi_hmi_controller_workspace_end_control(void *data, + struct ivi_hmi_controller *hmi_ctrl, + int32_t is_controlled) +{ + struct wlContextCommon *pCtx = data; + const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface); + + if (is_controlled) + return; + + /** + * During being controlled by hmi-controller, any input event is not + * notified. So when control ends with touch up, it invokes launcher + * if up event happens on a launcher surface. + * + */ + if (launcher_button(id_surface, &pCtx->hmi_setting->launcher_list)) { + pCtx->is_home_on = 0; + ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF); + } +} + +static const struct ivi_hmi_controller_listener hmi_controller_listener = { + ivi_hmi_controller_workspace_end_control +}; + +/** + * Registration of interfaces + */ +static void +registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, + const char *interface, uint32_t version) +{ + struct wlContextCommon *p_wlCtx = (struct wlContextCommon*)data; + + if (!strcmp(interface, "wl_compositor")) { + p_wlCtx->wlCompositor = + wl_registry_bind(registry, name, + &wl_compositor_interface, 1); + } else if (!strcmp(interface, "wl_shm")) { + p_wlCtx->wlShm = + wl_registry_bind(registry, name, &wl_shm_interface, 1); + wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx); + } else if (!strcmp(interface, "wl_seat")) { + p_wlCtx->wlSeat = + wl_registry_bind(registry, name, &wl_seat_interface, 1); + wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data); + } else if (!strcmp(interface, "ivi_application")) { + p_wlCtx->iviApplication = + wl_registry_bind(registry, name, + &ivi_application_interface, 1); + } else if (!strcmp(interface, "ivi_hmi_controller")) { + p_wlCtx->hmiCtrl = + wl_registry_bind(registry, name, + &ivi_hmi_controller_interface, 1); + + ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl, + &hmi_controller_listener, p_wlCtx); + } +} + +static void +registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static void +frame_listener_func(void *data, struct wl_callback *callback, uint32_t time) +{ + if (callback) + wl_callback_destroy(callback); +} + +static const struct wl_callback_listener frame_listener = { + frame_listener_func +}; + +/* + * The following correspondences between file names and cursors was copied + * from: https://bugs.kde.org/attachment.cgi?id=67313 + */ +static const char *bottom_left_corners[] = { + "bottom_left_corner", + "sw-resize", + "size_bdiag" +}; + +static const char *bottom_right_corners[] = { + "bottom_right_corner", + "se-resize", + "size_fdiag" +}; + +static const char *bottom_sides[] = { + "bottom_side", + "s-resize", + "size_ver" +}; + +static const char *grabbings[] = { + "grabbing", + "closedhand", + "208530c400c041818281048008011002" +}; + +static const char *left_ptrs[] = { + "left_ptr", + "default", + "top_left_arrow", + "left-arrow" +}; + +static const char *left_sides[] = { + "left_side", + "w-resize", + "size_hor" +}; + +static const char *right_sides[] = { + "right_side", + "e-resize", + "size_hor" +}; + +static const char *top_left_corners[] = { + "top_left_corner", + "nw-resize", + "size_fdiag" +}; + +static const char *top_right_corners[] = { + "top_right_corner", + "ne-resize", + "size_bdiag" +}; + +static const char *top_sides[] = { + "top_side", + "n-resize", + "size_ver" +}; + +static const char *xterms[] = { + "xterm", + "ibeam", + "text" +}; + +static const char *hand1s[] = { + "hand1", + "pointer", + "pointing_hand", + "e29285e634086352946a0e7090d73106" +}; + +static const char *watches[] = { + "watch", + "wait", + "0426c94ea35c87780ff01dc239897213" +}; + +struct cursor_alternatives { + const char **names; + size_t count; +}; + +static const struct cursor_alternatives cursors[] = { + { bottom_left_corners, ARRAY_LENGTH(bottom_left_corners) }, + { bottom_right_corners, ARRAY_LENGTH(bottom_right_corners) }, + { bottom_sides, ARRAY_LENGTH(bottom_sides) }, + { grabbings, ARRAY_LENGTH(grabbings) }, + { left_ptrs, ARRAY_LENGTH(left_ptrs) }, + { left_sides, ARRAY_LENGTH(left_sides) }, + { right_sides, ARRAY_LENGTH(right_sides) }, + { top_left_corners, ARRAY_LENGTH(top_left_corners) }, + { top_right_corners, ARRAY_LENGTH(top_right_corners) }, + { top_sides, ARRAY_LENGTH(top_sides) }, + { xterms, ARRAY_LENGTH(xterms) }, + { hand1s, ARRAY_LENGTH(hand1s) }, + { watches, ARRAY_LENGTH(watches) }, +}; + +static void +create_cursors(struct wlContextCommon *cmm) +{ + uint32_t i = 0; + uint32_t j = 0; + struct wl_cursor *cursor = NULL; + char *cursor_theme = cmm->hmi_setting->cursor_theme; + int32_t cursor_size = cmm->hmi_setting->cursor_size; + + cmm->cursor_theme = wl_cursor_theme_load(cursor_theme, cursor_size, + cmm->wlShm); + + cmm->cursors = + MEM_ALLOC(ARRAY_LENGTH(cursors) * sizeof(cmm->cursors[0])); + + for (i = 0; i < ARRAY_LENGTH(cursors); i++) { + cursor = NULL; + + for (j = 0; !cursor && j < cursors[i].count; ++j) { + cursor = wl_cursor_theme_get_cursor( + cmm->cursor_theme, cursors[i].names[j]); + } + + if (!cursor) { + fprintf(stderr, "could not load cursor '%s'\n", + cursors[i].names[0]); + } + + cmm->cursors[i] = cursor; + } +} + +static void +destroy_cursors(struct wlContextCommon *cmm) +{ + if (cmm->cursor_theme) + wl_cursor_theme_destroy(cmm->cursor_theme); + + free(cmm->cursors); +} + +/** + * Internal method to prepare parts of UI + */ +static void +createShmBuffer(struct wlContextStruct *p_wlCtx) +{ + struct wl_shm_pool *pool; + + int fd = -1; + int size = 0; + int width = 0; + int height = 0; + int stride = 0; + + width = cairo_image_surface_get_width(p_wlCtx->ctx_image); + height = cairo_image_surface_get_height(p_wlCtx->ctx_image); + stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image); + + size = stride * height; + + fd = os_create_anonymous_file(size); + if (fd < 0) { + fprintf(stderr, "creating a buffer file for %d B failed: %m\n", + size); + return ; + } + + p_wlCtx->data = + mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + if (MAP_FAILED == p_wlCtx->data) { + fprintf(stderr, "mmap failed: %m\n"); + close(fd); + return; + } + + pool = wl_shm_create_pool(p_wlCtx->cmm->wlShm, fd, size); + p_wlCtx->wlBuffer = wl_shm_pool_create_buffer(pool, 0, + width, + height, + stride, + WL_SHM_FORMAT_ARGB8888); + + if (NULL == p_wlCtx->wlBuffer) { + fprintf(stderr, "wl_shm_create_buffer failed: %m\n"); + close(fd); + return; + } + + wl_shm_pool_destroy(pool); + close(fd); +} + +static void +destroyWLContextCommon(struct wlContextCommon *p_wlCtx) +{ + destroy_cursors(p_wlCtx); + + if (p_wlCtx->pointer_surface) + wl_surface_destroy(p_wlCtx->pointer_surface); + + if (p_wlCtx->wlCompositor) + wl_compositor_destroy(p_wlCtx->wlCompositor); +} + +static void +destroyWLContextStruct(struct wlContextStruct *p_wlCtx) +{ + if (p_wlCtx->wlSurface) + wl_surface_destroy(p_wlCtx->wlSurface); + + if (p_wlCtx->ctx_image) { + cairo_surface_destroy(p_wlCtx->ctx_image); + p_wlCtx->ctx_image = NULL; + } +} + +static int +createSurface(struct wlContextStruct *p_wlCtx) +{ + p_wlCtx->wlSurface = + wl_compositor_create_surface(p_wlCtx->cmm->wlCompositor); + if (NULL == p_wlCtx->wlSurface) { + printf("Error: wl_compositor_create_surface failed.\n"); + destroyWLContextCommon(p_wlCtx->cmm); + abort(); + } + + return 0; +} + +static void +drawImage(struct wlContextStruct *p_wlCtx) +{ + struct wl_callback *callback; + + int width = 0; + int height = 0; + int stride = 0; + void *data = NULL; + + width = cairo_image_surface_get_width(p_wlCtx->ctx_image); + height = cairo_image_surface_get_height(p_wlCtx->ctx_image); + stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image); + data = cairo_image_surface_get_data(p_wlCtx->ctx_image); + + memcpy(p_wlCtx->data, data, stride * height); + + wl_surface_attach(p_wlCtx->wlSurface, p_wlCtx->wlBuffer, 0, 0); + wl_surface_damage(p_wlCtx->wlSurface, 0, 0, width, height); + + callback = wl_surface_frame(p_wlCtx->wlSurface); + wl_callback_add_listener(callback, &frame_listener, NULL); + + wl_surface_commit(p_wlCtx->wlSurface); +} + +static void +create_ivisurface(struct wlContextStruct *p_wlCtx, + uint32_t id_surface, + cairo_surface_t *surface) +{ + struct ivi_surface *ivisurf = NULL; + + p_wlCtx->ctx_image = surface; + + p_wlCtx->id_surface = id_surface; + wl_list_init(&p_wlCtx->link); + wl_list_insert(&p_wlCtx->cmm->list_wlContextStruct, &p_wlCtx->link); + + createSurface(p_wlCtx); + createShmBuffer(p_wlCtx); + + ivisurf = ivi_application_surface_create(p_wlCtx->cmm->iviApplication, + id_surface, + p_wlCtx->wlSurface); + if (ivisurf == NULL) { + fprintf(stderr, "Failed to create ivi_client_surface\n"); + return; + } + + drawImage(p_wlCtx); +} + +static void +create_ivisurfaceFromFile(struct wlContextStruct *p_wlCtx, + uint32_t id_surface, + const char *imageFile) +{ + cairo_surface_t *surface = load_cairo_surface(imageFile); + + if (NULL == surface) { + fprintf(stderr, "Failed to load_cairo_surface %s\n", imageFile); + return; + } + + create_ivisurface(p_wlCtx, id_surface, surface); +} + +static void +set_hex_color(cairo_t *cr, uint32_t color) +{ + cairo_set_source_rgba(cr, + ((color >> 16) & 0xff) / 255.0, + ((color >> 8) & 0xff) / 255.0, + ((color >> 0) & 0xff) / 255.0, + ((color >> 24) & 0xff) / 255.0); +} + +static void +create_ivisurfaceFromColor(struct wlContextStruct *p_wlCtx, + uint32_t id_surface, + uint32_t width, uint32_t height, + uint32_t color) +{ + cairo_surface_t *surface = NULL; + cairo_t *cr = NULL; + + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + width, height); + + cr = cairo_create(surface); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_rectangle(cr, 0, 0, width, height); + set_hex_color(cr, color); + cairo_fill(cr); + cairo_destroy(cr); + + create_ivisurface(p_wlCtx, id_surface, surface); +} + +static void +UI_ready(struct ivi_hmi_controller *controller) +{ + ivi_hmi_controller_UI_ready(controller); +} + +/** + * Internal method to set up UI by using ivi-hmi-controller + */ +static void +create_background(struct wlContextStruct *p_wlCtx, const uint32_t id_surface, + const char *imageFile) +{ + create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile); +} + +static void +create_panel(struct wlContextStruct *p_wlCtx, const uint32_t id_surface, + const char *imageFile) +{ + create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile); +} + +static void +create_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface, + const char *imageFile, uint32_t number) +{ + create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile); +} + +static void +create_home_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface, + const char *imageFile) +{ + create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile); +} + +static void +create_workspace_background(struct wlContextStruct *p_wlCtx, + struct hmi_homescreen_srf *srf) +{ + create_ivisurfaceFromColor(p_wlCtx, srf->id, 1, 1, srf->color); +} + +static void +create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list) +{ + struct hmi_homescreen_launcher **launchers; + struct hmi_homescreen_launcher *launcher = NULL; + + int launcher_count = wl_list_length(launcher_list); + int ii = 0; + int start = 0; + + if (0 == launcher_count) + return; + + launchers = MEM_ALLOC(launcher_count * sizeof(*launchers)); + + wl_list_for_each(launcher, launcher_list, link) { + launchers[ii] = launcher; + ii++; + } + + for (ii = 0; ii < launcher_count; ii++) { + int jj = 0; + + if (ii != launcher_count - 1 && + launchers[ii]->workspace_id == + launchers[ii + 1]->workspace_id) + continue; + + for (jj = start; jj <= ii; jj++) { + struct wlContextStruct *p_wlCtx; + + p_wlCtx = MEM_ALLOC(sizeof(*p_wlCtx)); + p_wlCtx->cmm = cmm; + create_ivisurfaceFromFile(p_wlCtx, + launchers[jj]->icon_surface_id, + launchers[jj]->icon); + } + + start = ii + 1; + } + + free(launchers); +} + +/** + * Internal method to read out weston.ini to get configuration + */ +static struct hmi_homescreen_setting * +hmi_homescreen_setting_create(void) +{ + struct weston_config *config = NULL; + struct weston_config_section *shellSection = NULL; + struct hmi_homescreen_setting *setting = MEM_ALLOC(sizeof(*setting)); + struct weston_config_section *section = NULL; + const char *name = NULL; + uint32_t workspace_layer_id; + uint32_t icon_surface_id = 0; + + wl_list_init(&setting->workspace_list); + wl_list_init(&setting->launcher_list); + + config = weston_config_parse("weston.ini"); + + shellSection = + weston_config_get_section(config, "ivi-shell", NULL, NULL); + + weston_config_section_get_string( + shellSection, "cursor-theme", &setting->cursor_theme, NULL); + + weston_config_section_get_int( + shellSection, "cursor-size", &setting->cursor_size, 32); + + weston_config_section_get_uint( + shellSection, "workspace-layer-id", &workspace_layer_id, 3000); + + weston_config_section_get_string( + shellSection, "background-image", &setting->background.filePath, + DATADIR "/weston/background.png"); + + weston_config_section_get_uint( + shellSection, "background-id", &setting->background.id, 1001); + + weston_config_section_get_string( + shellSection, "panel-image", &setting->panel.filePath, + DATADIR "/weston/panel.png"); + + weston_config_section_get_uint( + shellSection, "panel-id", &setting->panel.id, 1002); + + weston_config_section_get_string( + shellSection, "tiling-image", &setting->tiling.filePath, + DATADIR "/weston/tiling.png"); + + weston_config_section_get_uint( + shellSection, "tiling-id", &setting->tiling.id, 1003); + + weston_config_section_get_string( + shellSection, "sidebyside-image", &setting->sidebyside.filePath, + DATADIR "/weston/sidebyside.png"); + + weston_config_section_get_uint( + shellSection, "sidebyside-id", &setting->sidebyside.id, 1004); + + weston_config_section_get_string( + shellSection, "fullscreen-image", &setting->fullscreen.filePath, + DATADIR "/weston/fullscreen.png"); + + weston_config_section_get_uint( + shellSection, "fullscreen-id", &setting->fullscreen.id, 1005); + + weston_config_section_get_string( + shellSection, "random-image", &setting->random.filePath, + DATADIR "/weston/random.png"); + + weston_config_section_get_uint( + shellSection, "random-id", &setting->random.id, 1006); + + weston_config_section_get_string( + shellSection, "home-image", &setting->home.filePath, + DATADIR "/weston/home.png"); + + weston_config_section_get_uint( + shellSection, "home-id", &setting->home.id, 1007); + + weston_config_section_get_uint( + shellSection, "workspace-background-color", + &setting->workspace_background.color, 0x99000000); + + weston_config_section_get_uint( + shellSection, "workspace-background-id", + &setting->workspace_background.id, 2001); + + icon_surface_id = workspace_layer_id + 1; + + while (weston_config_next_section(config, §ion, &name)) { + struct hmi_homescreen_launcher *launcher; + + if (strcmp(name, "ivi-launcher") != 0) + continue; + + launcher = MEM_ALLOC(sizeof(*launcher)); + wl_list_init(&launcher->link); + + weston_config_section_get_string(section, "icon", + &launcher->icon, NULL); + weston_config_section_get_string(section, "path", + &launcher->path, NULL); + weston_config_section_get_uint(section, "workspace-id", + &launcher->workspace_id, 0); + weston_config_section_get_uint(section, "icon-id", + &launcher->icon_surface_id, + icon_surface_id); + icon_surface_id++; + + wl_list_insert(setting->launcher_list.prev, &launcher->link); + } + + weston_config_destroy(config); + return setting; +} + +/** + * Main thread + * + * The basic flow are as followed, + * 1/ read configuration from weston.ini by hmi_homescreen_setting_create + * 2/ draw png file to surface according to configuration of weston.ini and + * set up UI by using ivi-hmi-controller protocol by each create_* method + */ +int main(int argc, char **argv) +{ + struct wlContextCommon wlCtxCommon; + struct wlContextStruct wlCtx_BackGround; + struct wlContextStruct wlCtx_Panel; + struct wlContextStruct wlCtx_Button_1; + struct wlContextStruct wlCtx_Button_2; + struct wlContextStruct wlCtx_Button_3; + struct wlContextStruct wlCtx_Button_4; + struct wlContextStruct wlCtx_HomeButton; + struct wlContextStruct wlCtx_WorkSpaceBackGround; + struct wl_list launcher_wlCtxList; + int ret = 0; + struct hmi_homescreen_setting *hmi_setting; + struct wlContextStruct *pWlCtxSt = NULL; + + hmi_setting = hmi_homescreen_setting_create(); + + memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon)); + memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround)); + memset(&wlCtx_Panel, 0x00, sizeof(wlCtx_Panel)); + memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1)); + memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2)); + memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3)); + memset(&wlCtx_Button_4, 0x00, sizeof(wlCtx_Button_4)); + memset(&wlCtx_HomeButton, 0x00, sizeof(wlCtx_HomeButton)); + memset(&wlCtx_WorkSpaceBackGround, 0x00, + sizeof(wlCtx_WorkSpaceBackGround)); + wl_list_init(&launcher_wlCtxList); + wl_list_init(&wlCtxCommon.list_wlContextStruct); + + wlCtxCommon.hmi_setting = hmi_setting; + + wlCtxCommon.wlDisplay = wl_display_connect(NULL); + if (NULL == wlCtxCommon.wlDisplay) { + printf("Error: wl_display_connect failed.\n"); + return -1; + } + + /* get wl_registry */ + wlCtxCommon.formats = 0; + wlCtxCommon.wlRegistry = wl_display_get_registry(wlCtxCommon.wlDisplay); + wl_registry_add_listener(wlCtxCommon.wlRegistry, + ®istry_listener, &wlCtxCommon); + wl_display_roundtrip(wlCtxCommon.wlDisplay); + + if (wlCtxCommon.wlShm == NULL) { + fprintf(stderr, "No wl_shm global\n"); + exit(1); + } + + wl_display_roundtrip(wlCtxCommon.wlDisplay); + + if (!(wlCtxCommon.formats & (1 << WL_SHM_FORMAT_XRGB8888))) { + fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n"); + exit(1); + } + + if (wlCtxCommon.hmi_setting->cursor_theme) { + create_cursors(&wlCtxCommon); + + wlCtxCommon.pointer_surface = + wl_compositor_create_surface(wlCtxCommon.wlCompositor); + + wlCtxCommon.current_cursor = CURSOR_LEFT_PTR; + } + + wlCtx_BackGround.cmm = &wlCtxCommon; + wlCtx_Panel.cmm = &wlCtxCommon; + wlCtx_Button_1.cmm = &wlCtxCommon; + wlCtx_Button_2.cmm = &wlCtxCommon; + wlCtx_Button_3.cmm = &wlCtxCommon; + wlCtx_Button_4.cmm = &wlCtxCommon; + wlCtx_HomeButton.cmm = &wlCtxCommon; + wlCtx_WorkSpaceBackGround.cmm = &wlCtxCommon; + + /* create desktop widgets */ + create_background(&wlCtx_BackGround, hmi_setting->background.id, + hmi_setting->background.filePath); + + create_panel(&wlCtx_Panel, hmi_setting->panel.id, + hmi_setting->panel.filePath); + + create_button(&wlCtx_Button_1, hmi_setting->tiling.id, + hmi_setting->tiling.filePath, 0); + + create_button(&wlCtx_Button_2, hmi_setting->sidebyside.id, + hmi_setting->sidebyside.filePath, 1); + + create_button(&wlCtx_Button_3, hmi_setting->fullscreen.id, + hmi_setting->fullscreen.filePath, 2); + + create_button(&wlCtx_Button_4, hmi_setting->random.id, + hmi_setting->random.filePath, 3); + + create_workspace_background(&wlCtx_WorkSpaceBackGround, + &hmi_setting->workspace_background); + + create_launchers(&wlCtxCommon, &hmi_setting->launcher_list); + + create_home_button(&wlCtx_HomeButton, hmi_setting->home.id, + hmi_setting->home.filePath); + + UI_ready(wlCtxCommon.hmiCtrl); + + while (ret != -1) + ret = wl_display_dispatch(wlCtxCommon.wlDisplay); + + wl_list_for_each(pWlCtxSt, &wlCtxCommon.list_wlContextStruct, link) { + destroyWLContextStruct(pWlCtxSt); + } + + destroyWLContextCommon(&wlCtxCommon); + + return 0; +} diff --git a/clients/simple-egl.c b/clients/simple-egl.c index 0d4673b..8634075 100644 --- a/clients/simple-egl.c +++ b/clients/simple-egl.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,8 @@ #include #include "xdg-shell-client-protocol.h" +#include "ivi-application-client-protocol.h" +#define IVI_SURFACE_ID 9000 #ifndef EGL_EXT_swap_buffers_with_damage #define EGL_EXT_swap_buffers_with_damage 1 @@ -74,6 +77,7 @@ struct display { EGLConfig conf; } egl; struct window *window; + struct ivi_application *ivi_application; PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage; }; @@ -95,6 +99,7 @@ struct window { struct wl_egl_window *native; struct wl_surface *surface; struct xdg_surface *xdg_surface; + struct ivi_surface *ivi_surface; EGLSurface egl_surface; struct wl_callback *callback; int fullscreen, opaque, buffer_size, frame_sync; @@ -329,18 +334,61 @@ static const struct xdg_surface_listener xdg_surface_listener = { }; static void -create_surface(struct window *window) +handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface, + int32_t width, int32_t height) +{ + struct window *window = data; + + wl_egl_window_resize(window->native, width, height, 0, 0); + + window->geometry.width = width; + window->geometry.height = height; + + if (!window->fullscreen) + window->window_size = window->geometry; +} + +static const struct ivi_surface_listener ivi_surface_listener = { + handle_ivi_surface_configure, +}; + +static void +create_xdg_surface(struct window *window, struct display *display) { - struct display *display = window->display; - EGLBoolean ret; - - window->surface = wl_compositor_create_surface(display->compositor); window->xdg_surface = xdg_shell_get_xdg_surface(display->shell, window->surface); xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window); + xdg_surface_set_title(window->xdg_surface, "simple-egl"); +} + +static void +create_ivi_surface(struct window *window, struct display *display) +{ + uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid(); + window->ivi_surface = + ivi_application_surface_create(display->ivi_application, + id_ivisurf, window->surface); + + if (window->ivi_surface == NULL) { + fprintf(stderr, "Failed to create ivi_client_surface\n"); + abort(); + } + + ivi_surface_add_listener(window->ivi_surface, + &ivi_surface_listener, window); +} + +static void +create_surface(struct window *window) +{ + struct display *display = window->display; + EGLBoolean ret; + + window->surface = wl_compositor_create_surface(display->compositor); + window->native = wl_egl_window_create(window->surface, window->window_size.width, @@ -350,7 +398,13 @@ create_surface(struct window *window) display->egl.conf, window->native, NULL); - xdg_surface_set_title(window->xdg_surface, "simple-egl"); + if (display->shell) { + create_xdg_surface(window, display); + } else if (display->ivi_application) { + create_ivi_surface(window, display); + } else { + assert(0); + } ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface, window->egl_surface, window->display->egl.ctx); @@ -375,7 +429,10 @@ destroy_surface(struct window *window) eglDestroySurface(window->display->egl.dpy, window->egl_surface); wl_egl_window_destroy(window->native); - xdg_surface_destroy(window->xdg_surface); + if (window->xdg_surface) + xdg_surface_destroy(window->xdg_surface); + if (window->display->ivi_application) + ivi_surface_destroy(window->ivi_surface); wl_surface_destroy(window->surface); if (window->callback) @@ -729,6 +786,10 @@ registry_handle_global(void *data, struct wl_registry *registry, fprintf(stderr, "unable to load default left pointer\n"); // TODO: abort ? } + } else if (strcmp(interface, "ivi_application") == 0) { + d->ivi_application = + wl_registry_bind(registry, name, + &ivi_application_interface, 1); } } @@ -834,6 +895,9 @@ main(int argc, char **argv) if (display.shell) xdg_shell_destroy(display.shell); + if (display.ivi_application) + ivi_application_destroy(display.ivi_application); + if (display.compositor) wl_compositor_destroy(display.compositor); diff --git a/clients/simple-shm.c b/clients/simple-shm.c index 2087a0e..97c2da5 100644 --- a/clients/simple-shm.c +++ b/clients/simple-shm.c @@ -36,6 +36,8 @@ #include "../shared/os-compatibility.h" #include "xdg-shell-client-protocol.h" #include "fullscreen-shell-client-protocol.h" +#include "ivi-application-client-protocol.h" +#define IVI_SURFACE_ID 9000 struct display { struct wl_display *display; @@ -45,6 +47,7 @@ struct display { struct _wl_fullscreen_shell *fshell; struct wl_shm *shm; uint32_t formats; + struct ivi_application *ivi_application; }; struct buffer { @@ -58,6 +61,7 @@ struct window { int width, height; struct wl_surface *surface; struct xdg_surface *xdg_surface; + struct ivi_surface *ivi_surface; struct buffer buffers[2]; struct buffer *prev_buffer; struct wl_callback *callback; @@ -153,6 +157,17 @@ static const struct xdg_surface_listener xdg_surface_listener = { handle_delete, }; +static void +handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface, + int32_t width, int32_t height) +{ + /* Simple-shm is resizable */ +} + +static const struct ivi_surface_listener ivi_surface_listener = { + handle_ivi_surface_configure, +}; + static struct window * create_window(struct display *display, int width, int height) { @@ -184,6 +199,18 @@ create_window(struct display *display, int width, int height) window->surface, _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT, NULL); + } else if (display->ivi_application) { + uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid(); + window->ivi_surface = + ivi_application_surface_create(display->ivi_application, + id_ivisurf, window->surface); + if (window->ivi_surface == NULL) { + fprintf(stderr, "Failed to create ivi_client_surface\n"); + abort(); + } + + ivi_surface_add_listener(window->ivi_surface, + &ivi_surface_listener, window); } else { assert(0); } @@ -368,6 +395,10 @@ registry_handle_global(void *data, struct wl_registry *registry, d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); wl_shm_add_listener(d->shm, &shm_listener, d); + } else if (strcmp(interface, "ivi_application") == 0) { + d->ivi_application = + wl_registry_bind(registry, id, + &ivi_application_interface, 1); } } @@ -472,6 +503,12 @@ main(int argc, char **argv) ret = wl_display_dispatch(display->display); fprintf(stderr, "simple-shm exiting\n"); + + if (window->display->ivi_application) { + ivi_surface_destroy(window->ivi_surface); + ivi_application_destroy(window->display->ivi_application); + } + destroy_window(window); destroy_display(display); diff --git a/clients/window.c b/clients/window.c index 4592ef9..049093d 100644 --- a/clients/window.c +++ b/clients/window.c @@ -72,6 +72,9 @@ typedef void *EGLContext; #include "window.h" +#include "ivi-application-client-protocol.h" +#define IVI_SURFACE_ID 9000 + struct shm_pool; struct global { @@ -91,6 +94,7 @@ struct display { struct text_cursor_position *text_cursor_position; struct workspace_manager *workspace_manager; struct xdg_shell *xdg_shell; + struct ivi_application *ivi_application; /* ivi style shell */ EGLDisplay dpy; EGLConfig argb_config; EGLContext argb_ctx; @@ -246,6 +250,8 @@ struct window { struct window *transient_for; + struct ivi_surface *ivi_surface; + struct window_frame *frame; /* struct surface::link, contains also main_surface */ @@ -1368,6 +1374,19 @@ window_get_display(struct window *window) } static void +handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface, + int32_t width, int32_t height) +{ + struct window *window = data; + + window_schedule_resize(window, width, height); +} + +static const struct ivi_surface_listener ivi_surface_listener = { + handle_ivi_surface_configure, +}; + +static void surface_create_surface(struct surface *surface, uint32_t flags) { struct display *display = surface->window->display; @@ -1515,6 +1534,9 @@ window_destroy(struct window *window) if (window->xdg_popup) xdg_popup_destroy(window->xdg_popup); + if (window->ivi_surface) + ivi_surface_destroy(window->ivi_surface); + surface_destroy(window->main_surface); wl_list_remove(&window->link); @@ -4386,7 +4408,7 @@ window_create_internal(struct display *display, int custom) surface = surface_create(window); window->main_surface = surface; - assert(custom || display->xdg_shell); + assert(custom || display->xdg_shell || display->ivi_application); window->custom = custom; window->preferred_format = WINDOW_PREFERRED_FORMAT_NONE; @@ -4406,17 +4428,31 @@ struct window * window_create(struct display *display) { struct window *window; + uint32_t id_ivisurf; window = window_create_internal(display, 0); - window->xdg_surface = - xdg_shell_get_xdg_surface(window->display->xdg_shell, - window->main_surface->surface); - fail_on_null(window->xdg_surface); + if (window->display->xdg_shell) { + window->xdg_surface = + xdg_shell_get_xdg_surface(window->display->xdg_shell, + window->main_surface->surface); + fail_on_null(window->xdg_surface); - xdg_surface_set_user_data(window->xdg_surface, window); - xdg_surface_add_listener(window->xdg_surface, + xdg_surface_set_user_data(window->xdg_surface, window); + xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window); + } else if (display->ivi_application) { + /* auto generation of ivi_id based on process id + basement of id */ + id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid(); + window->ivi_surface = + ivi_application_surface_create(display->ivi_application, + id_ivisurf, window->main_surface->surface); + + fail_on_null(window->ivi_surface); + + ivi_surface_add_listener(window->ivi_surface, + &ivi_surface_listener, window); + } return window; } @@ -5090,6 +5126,10 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, d->subcompositor = wl_registry_bind(registry, id, &wl_subcompositor_interface, 1); + } else if (strcmp(interface, "ivi_application") == 0) { + d->ivi_application = + wl_registry_bind(registry, id, + &ivi_application_interface, 1); } if (d->global_handler) @@ -5389,6 +5429,9 @@ display_destroy(struct display *display) if (display->xdg_shell) xdg_shell_destroy(display->xdg_shell); + if (display->ivi_application) + ivi_application_destroy(display->ivi_application); + if (display->shm) wl_shm_destroy(display->shm); diff --git a/configure.ac b/configure.ac index f55cea8..edaba3c 100644 --- a/configure.ac +++ b/configure.ac @@ -433,6 +433,13 @@ if test "x$enable_dbus" != "xno"; then fi AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes") +# ivi-shell support +AC_ARG_ENABLE(ivi-shell, + AS_HELP_STRING([--disable-ivi-shell], + [do not build ivi-shell server plugin and client]),, + enable_ivi_shell=yes) +AM_CONDITIONAL(ENABLE_IVI_SHELL, test "x$enable_ivi_shell" = "xyes") + AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes) AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes) if test x$enable_wcap_tools = xyes; then @@ -522,6 +529,8 @@ AC_MSG_RESULT([ XWayland ${enable_xwayland} dbus ${enable_dbus} + ivi-shell ${enable_ivi_shell} + Build wcap utility ${enable_wcap_tools} Build Fullscreen Shell ${enable_fullscreen_shell} diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c new file mode 100644 index 0000000..7f3d5bf --- /dev/null +++ b/ivi-shell/hmi-controller.c @@ -0,0 +1,1814 @@ +/* + * Copyright (C) 2014 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. + */ + +/** + * A reference implementation how to use ivi-layout APIs in order to manage + * layout of ivi_surfaces/ivi_layers. Layout change is triggered by + * ivi-hmi-controller protocol, ivi-hmi-controller.xml. A reference how to + * use the protocol, see hmi-controller-homescreen. + * + * In-Vehicle Infotainment system usually manage properties of + * ivi_surfaces/ivi_layers by only a central component which decide where + * ivi_surfaces/ivi_layers shall be. This reference show examples to + * implement the central component as a module of weston. + * + * Default Scene graph of UI is defined in hmi_controller_create. It + * consists of + * - In the bottom, a base ivi_layer to group ivi_surfaces of background, + * panel, and buttons + * - Next, a application ivi_layer to show application ivi_surfaces. + * - Workspace background ivi_layer to show a ivi_surface of background image. + * - Workspace ivi_layer to show launcher to launch application with icons. + * Paths to binary and icon are defined in weston.ini. The width of this + * ivi_layer is longer than the size of ivi_screen because a workspace has + * several pages and is controlled by motion of input. + * + * TODO: animation method shall be refined + * TODO: support fade-in when UI is ready + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ivi-layout-export.h" +#include "ivi-hmi-controller-server-protocol.h" +#include "shared/helpers.h" + +/***************************************************************************** + * structure, globals + ****************************************************************************/ +struct hmi_controller_layer { + struct ivi_layout_layer *ivilayer; + uint32_t id_layer; + int32_t x; + int32_t y; + int32_t width; + int32_t height; +}; + +struct link_layer { + struct ivi_layout_layer *layout_layer; + struct wl_list link; +}; + +struct hmi_controller_fade { + uint32_t is_fade_in; + struct wl_list layer_list; +}; + +struct hmi_server_setting { + uint32_t base_layer_id; + uint32_t application_layer_id; + uint32_t workspace_background_layer_id; + uint32_t workspace_layer_id; + int32_t panel_height; + uint32_t transition_duration; + char *ivi_homescreen; +}; + +struct ui_setting { + uint32_t background_id; + uint32_t panel_id; + uint32_t tiling_id; + uint32_t sidebyside_id; + uint32_t fullscreen_id; + uint32_t random_id; + uint32_t home_id; + uint32_t workspace_background_id; +}; + +struct hmi_controller { + struct hmi_server_setting *hmi_setting; + struct hmi_controller_layer base_layer; + struct hmi_controller_layer application_layer; + struct hmi_controller_layer workspace_background_layer; + struct hmi_controller_layer workspace_layer; + enum ivi_hmi_controller_layout_mode layout_mode; + + struct hmi_controller_fade workspace_fade; + + int32_t workspace_count; + struct wl_array ui_widgets; + int32_t is_initialized; + + struct weston_compositor *compositor; + struct weston_process process; + struct wl_listener destroy_listener; + + struct wl_client *user_interface; + struct ui_setting ui_setting; +}; + +struct launcher_info { + uint32_t surface_id; + uint32_t workspace_id; + int32_t index; +}; + +const struct ivi_controller_interface *ivi_controller_interface; + +int +controller_module_init(struct weston_compositor *ec, + int *argc, char *argv[], + const struct ivi_controller_interface *interface, + size_t interface_version); + +/***************************************************************************** + * local functions + ****************************************************************************/ +static void * +fail_on_null(void *p, size_t size, char *file, int32_t line) +{ + if (size && !p) { + weston_log("%s(%d) %zd: out of memory\n", file, line, size); + exit(EXIT_FAILURE); + } + + return p; +} + +static void * +mem_alloc(size_t size, char *file, int32_t line) +{ + return fail_on_null(calloc(1, size), size, file, line); +} + +#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__) + +static int32_t +is_surf_in_ui_widget(struct hmi_controller *hmi_ctrl, + struct ivi_layout_surface *ivisurf) +{ + uint32_t id = ivi_controller_interface->get_id_of_surface(ivisurf); + + uint32_t *ui_widget_id = NULL; + wl_array_for_each(ui_widget_id, &hmi_ctrl->ui_widgets) { + if (*ui_widget_id == id) + return 1; + } + + return 0; +} + +static int +compare_launcher_info(const void *lhs, const void *rhs) +{ + const struct launcher_info *left = lhs; + const struct launcher_info *right = rhs; + + if (left->workspace_id < right->workspace_id) + return -1; + + if (left->workspace_id > right->workspace_id) + return 1; + + if (left->index < right->index) + return -1; + + if (left->index > right->index) + return 1; + + return 0; +} + +/** + * Internal methods called by mainly ivi_hmi_controller_switch_mode + * This reference shows 4 examples how to use ivi_layout APIs. + */ +static void +mode_divided_into_tiling(struct hmi_controller *hmi_ctrl, + struct ivi_layout_surface **pp_surface, + int32_t surface_length, + struct hmi_controller_layer *layer) +{ + const float surface_width = (float)layer->width * 0.25; + const float surface_height = (float)layer->height * 0.5; + int32_t surface_x = 0; + int32_t surface_y = 0; + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_surface **surfaces; + struct ivi_layout_surface **new_order; + const uint32_t duration = hmi_ctrl->hmi_setting->transition_duration; + + int32_t i = 0; + int32_t surf_num = 0; + uint32_t num = 1; + + surfaces = MEM_ALLOC(sizeof(*surfaces) * surface_length); + new_order = MEM_ALLOC(sizeof(*surfaces) * surface_length); + + for (i = 0; i < surface_length; i++) { + ivisurf = pp_surface[i]; + + /* skip ui widgets */ + if (is_surf_in_ui_widget(hmi_ctrl, ivisurf)) + continue; + + surfaces[surf_num++] = ivisurf; + } + + for (i = 0; i < surf_num; i++) { + ivisurf = surfaces[i]; + new_order[i] = ivisurf; + + if (num <= 8) { + if (num < 5) { + surface_x = (int32_t)((num - 1) * (surface_width)); + surface_y = 0; + } else { + surface_x = (int32_t)((num - 5) * (surface_width)); + surface_y = (int32_t)surface_height; + } + + ivi_controller_interface->surface_set_transition(ivisurf, + IVI_LAYOUT_TRANSITION_VIEW_DEFAULT, + duration); + ivi_controller_interface->surface_set_visibility(ivisurf, true); + ivi_controller_interface->surface_set_destination_rectangle(ivisurf, + surface_x, surface_y, + (int32_t)surface_width, + (int32_t)surface_height); + + num++; + continue; + } + ivi_controller_interface->surface_set_visibility(ivisurf, false); + } + + if (surf_num > 0) { + ivi_controller_interface->layer_set_transition(layer->ivilayer, + IVI_LAYOUT_TRANSITION_LAYER_VIEW_ORDER, + duration); + } + + free(surfaces); + free(new_order); +} + +static void +mode_divided_into_sidebyside(struct hmi_controller *hmi_ctrl, + struct ivi_layout_surface **pp_surface, + int32_t surface_length, + struct hmi_controller_layer *layer) +{ + int32_t surface_width = layer->width / 2; + int32_t surface_height = layer->height; + struct ivi_layout_surface *ivisurf = NULL; + + const uint32_t duration = hmi_ctrl->hmi_setting->transition_duration; + int32_t i = 0; + int32_t num = 1; + + for (i = 0; i < surface_length; i++) { + ivisurf = pp_surface[i]; + + /* skip ui widgets */ + if (is_surf_in_ui_widget(hmi_ctrl, ivisurf)) + continue; + + if (num == 1) { + ivi_controller_interface->surface_set_transition(ivisurf, + IVI_LAYOUT_TRANSITION_VIEW_DEFAULT, + duration); + ivi_controller_interface->surface_set_visibility(ivisurf, true); + ivi_controller_interface->surface_set_destination_rectangle(ivisurf, + 0, 0, + surface_width, + surface_height); + + num++; + continue; + } else if (num == 2) { + ivi_controller_interface->surface_set_transition(ivisurf, + IVI_LAYOUT_TRANSITION_VIEW_DEFAULT, + duration); + ivi_controller_interface->surface_set_visibility(ivisurf, true); + ivi_controller_interface->surface_set_destination_rectangle(ivisurf, + surface_width, 0, + surface_width, + surface_height); + + num++; + continue; + } + ivi_controller_interface->surface_set_transition(ivisurf, + IVI_LAYOUT_TRANSITION_VIEW_FADE_ONLY, + duration); + ivi_controller_interface->surface_set_visibility(ivisurf, false); + } +} + +static void +mode_fullscreen_someone(struct hmi_controller *hmi_ctrl, + struct ivi_layout_surface **pp_surface, + int32_t surface_length, + struct hmi_controller_layer *layer) +{ + const int32_t surface_width = layer->width; + const int32_t surface_height = layer->height; + struct ivi_layout_surface *ivisurf = NULL; + int32_t i = 0; + const uint32_t duration = hmi_ctrl->hmi_setting->transition_duration; + + for (i = 0; i < surface_length; i++) { + ivisurf = pp_surface[i]; + + /* skip ui widgets */ + if (is_surf_in_ui_widget(hmi_ctrl, ivisurf)) + continue; + + ivi_controller_interface->surface_set_transition(ivisurf, + IVI_LAYOUT_TRANSITION_VIEW_DEFAULT, + duration); + ivi_controller_interface->surface_set_visibility(ivisurf, true); + ivi_controller_interface->surface_set_destination_rectangle(ivisurf, 0, 0, + surface_width, + surface_height); + } +} + +static void +mode_random_replace(struct hmi_controller *hmi_ctrl, + struct ivi_layout_surface **pp_surface, + int32_t surface_length, + struct hmi_controller_layer *layer) +{ + const int32_t surface_width = (int32_t)(layer->width * 0.25f); + const int32_t surface_height = (int32_t)(layer->height * 0.25f); + int32_t surface_x = 0; + int32_t surface_y = 0; + struct ivi_layout_surface *ivisurf = NULL; + const uint32_t duration = hmi_ctrl->hmi_setting->transition_duration; + int32_t i = 0; + + for (i = 0; i < surface_length; i++) { + ivisurf = pp_surface[i]; + + /* skip ui widgets */ + if (is_surf_in_ui_widget(hmi_ctrl, ivisurf)) + continue; + + ivi_controller_interface->surface_set_transition(ivisurf, + IVI_LAYOUT_TRANSITION_VIEW_DEFAULT, + duration); + ivi_controller_interface->surface_set_visibility(ivisurf, true); + surface_x = rand() % (layer->width - surface_width); + surface_y = rand() % (layer->height - surface_height); + + ivi_controller_interface->surface_set_destination_rectangle(ivisurf, + surface_x, + surface_y, + surface_width, + surface_height); + } +} + +static int32_t +has_application_surface(struct hmi_controller *hmi_ctrl, + struct ivi_layout_surface **pp_surface, + int32_t surface_length) +{ + struct ivi_layout_surface *ivisurf = NULL; + int32_t i = 0; + + for (i = 0; i < surface_length; i++) { + ivisurf = pp_surface[i]; + + /* skip ui widgets */ + if (is_surf_in_ui_widget(hmi_ctrl, ivisurf)) + continue; + + return 1; + } + + return 0; +} + +/** + * Supports 4 example to layout of application ivi_surfaces; + * tiling, side by side, fullscreen, and random. + */ +static void +switch_mode(struct hmi_controller *hmi_ctrl, + enum ivi_hmi_controller_layout_mode layout_mode) +{ + struct hmi_controller_layer *layer = &hmi_ctrl->application_layer; + struct ivi_layout_surface **pp_surface = NULL; + int32_t surface_length = 0; + int32_t ret = 0; + + if (!hmi_ctrl->is_initialized) + return; + + hmi_ctrl->layout_mode = layout_mode; + + ret = ivi_controller_interface->get_surfaces(&surface_length, &pp_surface); + assert(!ret); + + if (!has_application_surface(hmi_ctrl, pp_surface, surface_length)) { + free(pp_surface); + pp_surface = NULL; + return; + } + + switch (layout_mode) { + case IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING: + mode_divided_into_tiling(hmi_ctrl, pp_surface, surface_length, + layer); + break; + case IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE: + mode_divided_into_sidebyside(hmi_ctrl, pp_surface, + surface_length, layer); + break; + case IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN: + mode_fullscreen_someone(hmi_ctrl, pp_surface, surface_length, + layer); + break; + case IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM: + mode_random_replace(hmi_ctrl, pp_surface, surface_length, + layer); + break; + } + + ivi_controller_interface->commit_changes(); + free(pp_surface); +} + +/** + * Internal method for transition + */ +static void +hmi_controller_fade_run(struct hmi_controller *hmi_ctrl, uint32_t is_fade_in, + struct hmi_controller_fade *fade) +{ + double tint = is_fade_in ? 1.0 : 0.0; + struct link_layer *linklayer = NULL; + const uint32_t duration = hmi_ctrl->hmi_setting->transition_duration; + + fade->is_fade_in = is_fade_in; + + wl_list_for_each(linklayer, &fade->layer_list, link) { + ivi_controller_interface->layer_set_transition(linklayer->layout_layer, + IVI_LAYOUT_TRANSITION_LAYER_FADE, + duration); + ivi_controller_interface->layer_set_fade_info(linklayer->layout_layer, + is_fade_in, 1.0 - tint, tint); + } +} + +/** + * Internal method to create ivi_layer with hmi_controller_layer and + * add to a ivi_screen + */ +static void +create_layer(struct ivi_layout_screen *iviscrn, + struct hmi_controller_layer *layer) +{ + int32_t ret = 0; + + layer->ivilayer = + ivi_controller_interface->layer_create_with_dimension(layer->id_layer, + layer->width, + layer->height); + assert(layer->ivilayer != NULL); + + ret = ivi_controller_interface->screen_add_layer(iviscrn, layer->ivilayer); + assert(!ret); + + ret = ivi_controller_interface->layer_set_destination_rectangle(layer->ivilayer, + layer->x, layer->y, + layer->width, + layer->height); + assert(!ret); + + ret = ivi_controller_interface->layer_set_visibility(layer->ivilayer, true); + assert(!ret); +} + +/** + * Internal set notification + */ +static void +set_notification_create_surface(struct ivi_layout_surface *ivisurf, + void *userdata) +{ + struct hmi_controller *hmi_ctrl = userdata; + struct ivi_layout_layer *application_layer = + hmi_ctrl->application_layer.ivilayer; + int32_t ret = 0; + + /* skip ui widgets */ + if (is_surf_in_ui_widget(hmi_ctrl, ivisurf)) + return; + + ret = ivi_controller_interface->layer_add_surface(application_layer, ivisurf); + assert(!ret); +} + +static void +set_notification_remove_surface(struct ivi_layout_surface *ivisurf, + void *userdata) +{ + struct hmi_controller *hmi_ctrl = userdata; + + switch_mode(hmi_ctrl, hmi_ctrl->layout_mode); +} + +static void +set_notification_configure_surface(struct ivi_layout_surface *ivisurf, + void *userdata) +{ + struct hmi_controller *hmi_ctrl = userdata; + struct ivi_layout_layer *application_layer = + hmi_ctrl->application_layer.ivilayer; + struct weston_surface *surface; + struct ivi_layout_surface **ivisurfs; + int32_t length = 0; + int32_t i; + + /* return if the surface is not application content */ + if (is_surf_in_ui_widget(hmi_ctrl, ivisurf)) { + return; + } + + /* + * if application changes size of wl_buffer. The source rectangle shall be + * fit to the size. + */ + surface = ivi_controller_interface->surface_get_weston_surface(ivisurf); + if (surface) { + ivi_controller_interface->surface_set_source_rectangle( + ivisurf, 0, 0, surface->width, + surface->height); + } + + /* + * search if the surface is already added to layer. + * If not yet, it is newly invoded application to go to switch_mode. + */ + ivi_controller_interface->get_surfaces_on_layer(application_layer, + &length, &ivisurfs); + for (i = 0; i < length; i++) { + if (ivisurf == ivisurfs[i]) { + /* + * if it is non new invoked application, just call + * commit_changes to apply source_rectangle. + */ + ivi_controller_interface->commit_changes(); + return; + } + } + + switch_mode(hmi_ctrl, hmi_ctrl->layout_mode); +} + +/** + * A hmi_controller used 4 ivi_layers to manage ivi_surfaces. The IDs of + * corresponding ivi_layer are defined in weston.ini. Default scene graph + * of ivi_layers are initialized in hmi_controller_create + */ +static struct hmi_server_setting * +hmi_server_setting_create(struct weston_compositor *ec) +{ + struct hmi_server_setting *setting = MEM_ALLOC(sizeof(*setting)); + struct weston_config *config = ec->config; + struct weston_config_section *shell_section = NULL; + + shell_section = weston_config_get_section(config, "ivi-shell", + NULL, NULL); + + weston_config_section_get_uint(shell_section, "base-layer-id", + &setting->base_layer_id, 1000); + + weston_config_section_get_uint(shell_section, + "workspace-background-layer-id", + &setting->workspace_background_layer_id, + 2000); + + weston_config_section_get_uint(shell_section, "workspace-layer-id", + &setting->workspace_layer_id, 3000); + + weston_config_section_get_uint(shell_section, "application-layer-id", + &setting->application_layer_id, 4000); + + weston_config_section_get_uint(shell_section, "transition-duration", + &setting->transition_duration, 300); + + setting->panel_height = 70; + + weston_config_section_get_string(shell_section, + "ivi-shell-user-interface", + &setting->ivi_homescreen, NULL); + + return setting; +} + +static void +hmi_controller_destroy(struct wl_listener *listener, void *data) +{ + struct link_layer *link = NULL; + struct link_layer *next = NULL; + struct hmi_controller *hmi_ctrl = + container_of(listener, struct hmi_controller, destroy_listener); + + wl_list_for_each_safe(link, next, + &hmi_ctrl->workspace_fade.layer_list, link) { + wl_list_remove(&link->link); + free(link); + } + + wl_array_release(&hmi_ctrl->ui_widgets); + free(hmi_ctrl->hmi_setting); + free(hmi_ctrl); +} + +/** + * This is a starting method called from module_init. + * This sets up scene graph of ivi_layers; base, application, workspace + * background, and workspace. These ivi_layers are created/added to + * ivi_screen in create_layer + * + * base: to group ivi_surfaces of panel and background + * application: to group ivi_surfaces of ivi_applications + * workspace background: to group a ivi_surface of background in workspace + * workspace: to group ivi_surfaces for launching ivi_applications + * + * ivi_layers of workspace background and workspace is set to invisible at + * first. The properties of it is updated with animation when + * ivi_hmi_controller_home is requested. + */ +static struct hmi_controller * +hmi_controller_create(struct weston_compositor *ec) +{ + struct ivi_layout_screen **pp_screen = NULL; + struct ivi_layout_screen *iviscrn = NULL; + int32_t screen_length = 0; + int32_t screen_width = 0; + int32_t screen_height = 0; + struct link_layer *tmp_link_layer = NULL; + int32_t panel_height = 0; + struct hmi_controller *hmi_ctrl = MEM_ALLOC(sizeof(*hmi_ctrl)); + + wl_array_init(&hmi_ctrl->ui_widgets); + hmi_ctrl->layout_mode = IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING; + hmi_ctrl->hmi_setting = hmi_server_setting_create(ec); + hmi_ctrl->compositor = ec; + + ivi_controller_interface->get_screens(&screen_length, &pp_screen); + + iviscrn = pp_screen[0]; + + ivi_controller_interface->get_screen_resolution(iviscrn, &screen_width, + &screen_height); + + /* init base ivi_layer*/ + hmi_ctrl->base_layer.x = 0; + hmi_ctrl->base_layer.y = 0; + hmi_ctrl->base_layer.width = screen_width; + hmi_ctrl->base_layer.height = screen_height; + hmi_ctrl->base_layer.id_layer = hmi_ctrl->hmi_setting->base_layer_id; + + create_layer(iviscrn, &hmi_ctrl->base_layer); + + panel_height = hmi_ctrl->hmi_setting->panel_height; + + /* init application ivi_layer */ + hmi_ctrl->application_layer.x = 0; + hmi_ctrl->application_layer.y = 0; + hmi_ctrl->application_layer.width = screen_width; + hmi_ctrl->application_layer.height = screen_height - panel_height; + hmi_ctrl->application_layer.id_layer = + hmi_ctrl->hmi_setting->application_layer_id; + + create_layer(iviscrn, &hmi_ctrl->application_layer); + + /* init workspace background ivi_layer */ + hmi_ctrl->workspace_background_layer.x = 0; + hmi_ctrl->workspace_background_layer.y = 0; + hmi_ctrl->workspace_background_layer.width = screen_width; + hmi_ctrl->workspace_background_layer.height = + screen_height - panel_height; + + hmi_ctrl->workspace_background_layer.id_layer = + hmi_ctrl->hmi_setting->workspace_background_layer_id; + + create_layer(iviscrn, &hmi_ctrl->workspace_background_layer); + ivi_controller_interface->layer_set_opacity( + hmi_ctrl->workspace_background_layer.ivilayer, 0); + ivi_controller_interface->layer_set_visibility( + hmi_ctrl->workspace_background_layer.ivilayer, false); + + + wl_list_init(&hmi_ctrl->workspace_fade.layer_list); + tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer)); + tmp_link_layer->layout_layer = + hmi_ctrl->workspace_background_layer.ivilayer; + wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, + &tmp_link_layer->link); + + ivi_controller_interface->add_notification_create_surface( + set_notification_create_surface, hmi_ctrl); + ivi_controller_interface->add_notification_remove_surface( + set_notification_remove_surface, hmi_ctrl); + ivi_controller_interface->add_notification_configure_surface( + set_notification_configure_surface, hmi_ctrl); + + hmi_ctrl->destroy_listener.notify = hmi_controller_destroy; + wl_signal_add(&hmi_ctrl->compositor->destroy_signal, + &hmi_ctrl->destroy_listener); + + free(pp_screen); + pp_screen = NULL; + + return hmi_ctrl; +} + +/** + * Implementations of ivi-hmi-controller.xml + */ + +/** + * A ivi_surface drawing background is identified by id_surface. + * Properties of the ivi_surface is set by using ivi_layout APIs according to + * the scene graph of UI defined in hmi_controller_create. + * + * UI ivi_layer is used to add this ivi_surface. + */ +static void +ivi_hmi_controller_set_background(struct hmi_controller *hmi_ctrl, + uint32_t id_surface) +{ + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer; + const int32_t dstx = hmi_ctrl->application_layer.x; + const int32_t dsty = hmi_ctrl->application_layer.y; + const int32_t width = hmi_ctrl->application_layer.width; + const int32_t height = hmi_ctrl->application_layer.height; + int32_t ret = 0; + + uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets, + sizeof(*add_surface_id)); + *add_surface_id = id_surface; + + ivisurf = ivi_controller_interface->get_surface_from_id(id_surface); + assert(ivisurf != NULL); + + ret = ivi_controller_interface->layer_add_surface(ivilayer, ivisurf); + assert(!ret); + + ret = ivi_controller_interface->surface_set_destination_rectangle(ivisurf, + dstx, dsty, width, height); + assert(!ret); + + ret = ivi_controller_interface->surface_set_visibility(ivisurf, true); + assert(!ret); +} + +/** + * A ivi_surface drawing panel is identified by id_surface. + * Properties of the ivi_surface is set by using ivi_layout APIs according to + * the scene graph of UI defined in hmi_controller_create. + * + * UI ivi_layer is used to add this ivi_surface. + */ +static void +ivi_hmi_controller_set_panel(struct hmi_controller *hmi_ctrl, + uint32_t id_surface) +{ + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer; + const int32_t width = hmi_ctrl->base_layer.width; + int32_t ret = 0; + int32_t panel_height = 0; + const int32_t dstx = 0; + int32_t dsty = 0; + + uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets, + sizeof(*add_surface_id)); + *add_surface_id = id_surface; + + ivisurf = ivi_controller_interface->get_surface_from_id(id_surface); + assert(ivisurf != NULL); + + ret = ivi_controller_interface->layer_add_surface(ivilayer, ivisurf); + assert(!ret); + + panel_height = hmi_ctrl->hmi_setting->panel_height; + + dsty = hmi_ctrl->base_layer.height - panel_height; + + ret = ivi_controller_interface->surface_set_destination_rectangle( + ivisurf, dstx, dsty, width, panel_height); + assert(!ret); + + ret = ivi_controller_interface->surface_set_visibility(ivisurf, true); + assert(!ret); +} + +/** + * A ivi_surface drawing buttons in panel is identified by id_surface. + * It can set several buttons. Properties of the ivi_surface is set by + * using ivi_layout APIs according to the scene graph of UI defined in + * hmi_controller_create. Additionally, the position of it is shifted to + * right when new one is requested. + * + * UI ivi_layer is used to add these ivi_surfaces. + */ +static void +ivi_hmi_controller_set_button(struct hmi_controller *hmi_ctrl, + uint32_t id_surface, int32_t number) +{ + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer; + const int32_t width = 48; + const int32_t height = 48; + int32_t ret = 0; + int32_t panel_height = 0; + int32_t dstx = 0; + int32_t dsty = 0; + uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets, + sizeof(*add_surface_id)); + *add_surface_id = id_surface; + + ivisurf = ivi_controller_interface->get_surface_from_id(id_surface); + assert(ivisurf != NULL); + + ret = ivi_controller_interface->layer_add_surface(ivilayer, ivisurf); + assert(!ret); + + panel_height = hmi_ctrl->hmi_setting->panel_height; + + dstx = (60 * number) + 15; + dsty = (hmi_ctrl->base_layer.height - panel_height) + 5; + + ret = ivi_controller_interface->surface_set_destination_rectangle( + ivisurf,dstx, dsty, width, height); + assert(!ret); + + ret = ivi_controller_interface->surface_set_visibility(ivisurf, true); + assert(!ret); +} + +/** + * A ivi_surface drawing home button in panel is identified by id_surface. + * Properties of the ivi_surface is set by using ivi_layout APIs according to + * the scene graph of UI defined in hmi_controller_create. + * + * UI ivi_layer is used to add these ivi_surfaces. + */ +static void +ivi_hmi_controller_set_home_button(struct hmi_controller *hmi_ctrl, + uint32_t id_surface) +{ + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer; + int32_t ret = 0; + int32_t size = 48; + int32_t panel_height = hmi_ctrl->hmi_setting->panel_height; + const int32_t dstx = (hmi_ctrl->base_layer.width - size) / 2; + const int32_t dsty = (hmi_ctrl->base_layer.height - panel_height) + 5; + + uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets, + sizeof(*add_surface_id)); + *add_surface_id = id_surface; + + ivisurf = ivi_controller_interface->get_surface_from_id(id_surface); + assert(ivisurf != NULL); + + ret = ivi_controller_interface->layer_add_surface(ivilayer, ivisurf); + assert(!ret); + + ret = ivi_controller_interface->surface_set_destination_rectangle( + ivisurf, dstx, dsty, size, size); + assert(!ret); + + ret = ivi_controller_interface->surface_set_visibility(ivisurf, true); + assert(!ret); +} + +/** + * A ivi_surface drawing background of workspace is identified by id_surface. + * Properties of the ivi_surface is set by using ivi_layout APIs according to + * the scene graph of UI defined in hmi_controller_create. + * + * A ivi_layer of workspace_background is used to add this ivi_surface. + */ +static void +ivi_hmi_controller_set_workspacebackground(struct hmi_controller *hmi_ctrl, + uint32_t id_surface) +{ + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_layer *ivilayer = NULL; + const int32_t width = hmi_ctrl->workspace_background_layer.width; + const int32_t height = hmi_ctrl->workspace_background_layer.height; + int32_t ret = 0; + + uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets, + sizeof(*add_surface_id)); + *add_surface_id = id_surface; + ivilayer = hmi_ctrl->workspace_background_layer.ivilayer; + + ivisurf = ivi_controller_interface->get_surface_from_id(id_surface); + assert(ivisurf != NULL); + + ret = ivi_controller_interface->layer_add_surface(ivilayer, ivisurf); + assert(!ret); + + ret = ivi_controller_interface->surface_set_destination_rectangle(ivisurf, + 0, 0, width, height); + assert(!ret); + + ret = ivi_controller_interface->surface_set_visibility(ivisurf, true); + assert(!ret); +} + +/** + * A list of ivi_surfaces drawing launchers in workspace is identified by + * id_surfaces. Properties of the ivi_surface is set by using ivi_layout + * APIs according to the scene graph of UI defined in hmi_controller_create. + * + * The workspace can have several pages to group ivi_surfaces of launcher. + * Each call of this interface increments a number of page to add a group + * of ivi_surfaces + */ +static void +ivi_hmi_controller_add_launchers(struct hmi_controller *hmi_ctrl, + int32_t icon_size) +{ + int32_t minspace_x = 10; + int32_t minspace_y = minspace_x; + + int32_t width = hmi_ctrl->workspace_background_layer.width; + int32_t height = hmi_ctrl->workspace_background_layer.height; + + int32_t x_count = (width - minspace_x) / (minspace_x + icon_size); + int32_t space_x = (int32_t)((width - x_count * icon_size) / (1.0 + x_count)); + float fcell_size_x = icon_size + space_x; + + int32_t y_count = (height - minspace_y) / (minspace_y + icon_size); + int32_t space_y = (int32_t)((height - y_count * icon_size) / (1.0 + y_count)); + float fcell_size_y = icon_size + space_y; + + struct weston_config *config = NULL; + struct weston_config_section *section = NULL; + const char *name = NULL; + int launcher_count = 0; + struct wl_array launchers; + int32_t nx = 0; + int32_t ny = 0; + int32_t prev = -1; + struct launcher_info *data = NULL; + + uint32_t surfaceid = 0; + uint32_t workspaceid = 0; + struct launcher_info *info = NULL; + + int32_t x = 0; + int32_t y = 0; + int32_t ret = 0; + struct ivi_layout_surface* layout_surface = NULL; + uint32_t *add_surface_id = NULL; + + struct ivi_layout_screen *iviscrn = NULL; + struct link_layer *tmp_link_layer = NULL; + struct ivi_layout_screen **pp_screen = NULL; + int32_t screen_length = 0; + + if (0 == x_count) + x_count = 1; + + if (0 == y_count) + y_count = 1; + + config = hmi_ctrl->compositor->config; + if (!config) + return; + + section = weston_config_get_section(config, "ivi-shell", NULL, NULL); + if (!section) + return; + + wl_array_init(&launchers); + + while (weston_config_next_section(config, §ion, &name)) { + surfaceid = 0; + workspaceid = 0; + info = NULL; + if (0 != strcmp(name, "ivi-launcher")) + continue; + + if (0 != weston_config_section_get_uint(section, "icon-id", + &surfaceid, 0)) + continue; + + if (0 != weston_config_section_get_uint(section, + "workspace-id", + &workspaceid, 0)) + continue; + + info = wl_array_add(&launchers, sizeof(*info)); + + if (info) { + info->surface_id = surfaceid; + info->workspace_id = workspaceid; + info->index = launcher_count; + ++launcher_count; + } + } + + qsort(launchers.data, launcher_count, sizeof(struct launcher_info), + compare_launcher_info); + + wl_array_for_each(data, &launchers) { + x = 0; + y = 0; + ret = 0; + layout_surface = NULL; + add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets, + sizeof(*add_surface_id)); + + *add_surface_id = data->surface_id; + + if (0 > prev || (uint32_t)prev != data->workspace_id) { + nx = 0; + ny = 0; + prev = data->workspace_id; + + if (0 <= prev) + hmi_ctrl->workspace_count++; + } + + if (y_count == ny) { + ny = 0; + hmi_ctrl->workspace_count++; + } + + x = nx * fcell_size_x + (hmi_ctrl->workspace_count - 1) * width + space_x; + y = ny * fcell_size_y + space_y; + + layout_surface = + ivi_controller_interface->get_surface_from_id(data->surface_id); + assert(layout_surface); + + ret = ivi_controller_interface->surface_set_destination_rectangle( + layout_surface, x, y, icon_size, icon_size); + assert(!ret); + + nx++; + + if (x_count == nx) { + ny++; + nx = 0; + } + } + + /* init workspace ivi_layer */ + hmi_ctrl->workspace_layer.x = hmi_ctrl->workspace_background_layer.x; + hmi_ctrl->workspace_layer.y = hmi_ctrl->workspace_background_layer.y; + hmi_ctrl->workspace_layer.width = + hmi_ctrl->workspace_background_layer.width * hmi_ctrl->workspace_count; + hmi_ctrl->workspace_layer.height = + hmi_ctrl->workspace_background_layer.height; + hmi_ctrl->workspace_layer.id_layer = + hmi_ctrl->hmi_setting->workspace_layer_id; + + ivi_controller_interface->get_screens(&screen_length, &pp_screen); + iviscrn = pp_screen[0]; + free(pp_screen); + create_layer(iviscrn, &hmi_ctrl->workspace_layer); + ivi_controller_interface->layer_set_opacity(hmi_ctrl->workspace_layer.ivilayer, 0); + ivi_controller_interface->layer_set_visibility(hmi_ctrl->workspace_layer.ivilayer, + false); + + tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer)); + tmp_link_layer->layout_layer = hmi_ctrl->workspace_layer.ivilayer; + wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, + &tmp_link_layer->link); + + /* Add surface to layer */ + wl_array_for_each(data, &launchers) { + layout_surface = + ivi_controller_interface->get_surface_from_id(data->surface_id); + assert(layout_surface); + + ret = ivi_controller_interface->layer_add_surface(hmi_ctrl->workspace_layer.ivilayer, + layout_surface); + assert(!ret); + + ret = ivi_controller_interface->surface_set_visibility(layout_surface, true); + assert(!ret); + } + + wl_array_release(&launchers); + ivi_controller_interface->commit_changes(); +} + +static void +ivi_hmi_controller_UI_ready(struct wl_client *client, + struct wl_resource *resource) +{ + struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource); + + ivi_hmi_controller_set_background(hmi_ctrl, hmi_ctrl->ui_setting.background_id); + ivi_hmi_controller_set_panel(hmi_ctrl, hmi_ctrl->ui_setting.panel_id); + ivi_hmi_controller_set_button(hmi_ctrl, hmi_ctrl->ui_setting.tiling_id, 0); + ivi_hmi_controller_set_button(hmi_ctrl, hmi_ctrl->ui_setting.sidebyside_id, 1); + ivi_hmi_controller_set_button(hmi_ctrl, hmi_ctrl->ui_setting.fullscreen_id, 2); + ivi_hmi_controller_set_button(hmi_ctrl, hmi_ctrl->ui_setting.random_id, 3); + ivi_hmi_controller_set_home_button(hmi_ctrl, hmi_ctrl->ui_setting.home_id); + ivi_hmi_controller_set_workspacebackground(hmi_ctrl, hmi_ctrl->ui_setting.workspace_background_id); + ivi_controller_interface->commit_changes(); + + ivi_hmi_controller_add_launchers(hmi_ctrl, 256); + hmi_ctrl->is_initialized = 1; +} + +/** + * Implementation of request and event of ivi_hmi_controller_workspace_control + * and controlling workspace. + * + * When motion of input is detected in a ivi_surface of workspace background, + * ivi_hmi_controller_workspace_control shall be invoked and to start + * controlling of workspace. The workspace has several pages to show several + * groups of applications. + * The workspace is slid by using ivi-layout to select a a page in layer_set_pos + * according to motion. When motion finished, e.g. touch up detected, control is + * terminated and event:ivi_hmi_controller_workspace_control is notified. + */ +struct pointer_grab { + struct weston_pointer_grab grab; + struct ivi_layout_layer *layer; + struct wl_resource *resource; +}; + +struct touch_grab { + struct weston_touch_grab grab; + struct ivi_layout_layer *layer; + struct wl_resource *resource; +}; + +struct move_grab { + wl_fixed_t dst[2]; + wl_fixed_t rgn[2][2]; + double v[2]; + struct timespec start_time; + struct timespec pre_time; + wl_fixed_t start_pos[2]; + wl_fixed_t pos[2]; + int32_t is_moved; +}; + +struct pointer_move_grab { + struct pointer_grab base; + struct move_grab move; +}; + +struct touch_move_grab { + struct touch_grab base; + struct move_grab move; + int32_t is_active; +}; + +static void +pointer_grab_start(struct pointer_grab *grab, + struct ivi_layout_layer *layer, + const struct weston_pointer_grab_interface *interface, + struct weston_pointer *pointer) +{ + grab->grab.interface = interface; + grab->layer = layer; + weston_pointer_start_grab(pointer, &grab->grab); +} + +static void +touch_grab_start(struct touch_grab *grab, + struct ivi_layout_layer *layer, + const struct weston_touch_grab_interface *interface, + struct weston_touch* touch) +{ + grab->grab.interface = interface; + grab->layer = layer; + weston_touch_start_grab(touch, &grab->grab); +} + +static int32_t +clamp(int32_t val, int32_t min, int32_t max) +{ + if (val < min) + return min; + + if (max < val) + return max; + + return val; +} + +static void +move_workspace_grab_end(struct move_grab *move, struct wl_resource* resource, + wl_fixed_t grab_x, struct ivi_layout_layer *layer) +{ + struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource); + int32_t width = hmi_ctrl->workspace_background_layer.width; + + struct timespec time = {0}; + double grab_time = 0.0; + double from_motion_time = 0.0; + double pointer_v = 0.0; + int32_t is_flick = 0; + int32_t pos_x = 0; + int32_t pos_y = 0; + int page_no = 0; + double end_pos = 0.0; + uint32_t duration = 0; + + clock_gettime(CLOCK_MONOTONIC, &time); + + grab_time = 1e+3 * (time.tv_sec - move->start_time.tv_sec) + + 1e-6 * (time.tv_nsec - move->start_time.tv_nsec); + + from_motion_time = 1e+3 * (time.tv_sec - move->pre_time.tv_sec) + + 1e-6 * (time.tv_nsec - move->pre_time.tv_nsec); + + pointer_v = move->v[0]; + + is_flick = grab_time < 400 && 0.4 < fabs(pointer_v); + if (200 < from_motion_time) + pointer_v = 0.0; + + ivi_controller_interface->layer_get_position(layer, &pos_x, &pos_y); + + + if (is_flick) { + int orgx = wl_fixed_to_int(move->dst[0] + grab_x); + page_no = (-orgx + width / 2) / width; + + if (pointer_v < 0.0) + page_no++; + else + page_no--; + } else { + page_no = (-pos_x + width / 2) / width; + } + + page_no = clamp(page_no, 0, hmi_ctrl->workspace_count - 1); + end_pos = -page_no * width; + + duration = hmi_ctrl->hmi_setting->transition_duration; + ivi_hmi_controller_send_workspace_end_control(resource, move->is_moved); + ivi_controller_interface->layer_set_transition(layer, + IVI_LAYOUT_TRANSITION_LAYER_MOVE, + duration); + ivi_controller_interface->layer_set_destination_rectangle(layer, + end_pos, pos_y, + hmi_ctrl->workspace_layer.width, + hmi_ctrl->workspace_layer.height); + ivi_controller_interface->commit_changes(); +} + +static void +pointer_move_workspace_grab_end(struct pointer_grab *grab) +{ + struct pointer_move_grab *pnt_move_grab = + (struct pointer_move_grab *)grab; + struct ivi_layout_layer *layer = pnt_move_grab->base.layer; + + move_workspace_grab_end(&pnt_move_grab->move, grab->resource, + grab->grab.pointer->grab_x, layer); + + weston_pointer_end_grab(grab->grab.pointer); +} + +static void +touch_move_workspace_grab_end(struct touch_grab *grab) +{ + struct touch_move_grab *tch_move_grab = (struct touch_move_grab *)grab; + struct ivi_layout_layer *layer = tch_move_grab->base.layer; + + move_workspace_grab_end(&tch_move_grab->move, grab->resource, + grab->grab.touch->grab_x, layer); + + weston_touch_end_grab(grab->grab.touch); +} + +static void +pointer_noop_grab_focus(struct weston_pointer_grab *grab) +{ +} + +static void +move_grab_update(struct move_grab *move, wl_fixed_t pointer[2]) +{ + struct timespec timestamp = {0}; + int32_t ii = 0; + double dt = 0.0; + + clock_gettime(CLOCK_MONOTONIC, ×tamp); //FIXME + dt = (1e+3 * (timestamp.tv_sec - move->pre_time.tv_sec) + + 1e-6 * (timestamp.tv_nsec - move->pre_time.tv_nsec)); + + if (dt < 1e-6) + dt = 1e-6; + + move->pre_time = timestamp; + + for (ii = 0; ii < 2; ii++) { + wl_fixed_t prepos = move->pos[ii]; + move->pos[ii] = pointer[ii] + move->dst[ii]; + + if (move->pos[ii] < move->rgn[0][ii]) { + move->pos[ii] = move->rgn[0][ii]; + move->dst[ii] = move->pos[ii] - pointer[ii]; + } else if (move->rgn[1][ii] < move->pos[ii]) { + move->pos[ii] = move->rgn[1][ii]; + move->dst[ii] = move->pos[ii] - pointer[ii]; + } + + move->v[ii] = wl_fixed_to_double(move->pos[ii] - prepos) / dt; + + if (!move->is_moved && + 0 < wl_fixed_to_int(move->pos[ii] - move->start_pos[ii])) + move->is_moved = 1; + } +} + +static void +layer_set_pos(struct ivi_layout_layer *layer, wl_fixed_t pos_x, + wl_fixed_t pos_y) +{ + int32_t layout_pos_x = 0; + int32_t layout_pos_y = 0; + + layout_pos_x = wl_fixed_to_int(pos_x); + layout_pos_y = wl_fixed_to_int(pos_y); + ivi_controller_interface->layer_set_position(layer, layout_pos_x, layout_pos_y); + ivi_controller_interface->commit_changes(); +} + +static void +pointer_move_grab_motion(struct weston_pointer_grab *grab, uint32_t time, + wl_fixed_t x, wl_fixed_t y) +{ + struct pointer_move_grab *pnt_move_grab = + (struct pointer_move_grab *)grab; + wl_fixed_t pointer_pos[2] = {x, y}; + + move_grab_update(&pnt_move_grab->move, pointer_pos); + layer_set_pos(pnt_move_grab->base.layer, + pnt_move_grab->move.pos[0], pnt_move_grab->move.pos[1]); + weston_pointer_move(pnt_move_grab->base.grab.pointer, x, y); +} + +static void +touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time, + int touch_id, wl_fixed_t x, wl_fixed_t y) +{ + struct touch_move_grab *tch_move_grab = (struct touch_move_grab *)grab; + + if (!tch_move_grab->is_active) + return; + + wl_fixed_t pointer_pos[2] = { + grab->touch->grab_x, + grab->touch->grab_y + }; + + move_grab_update(&tch_move_grab->move, pointer_pos); + layer_set_pos(tch_move_grab->base.layer, + tch_move_grab->move.pos[0], tch_move_grab->move.pos[1]); +} + +static void +pointer_move_workspace_grab_button(struct weston_pointer_grab *grab, + uint32_t time, uint32_t button, + uint32_t state_w) +{ + if (BTN_LEFT == button && + WL_POINTER_BUTTON_STATE_RELEASED == state_w) { + struct pointer_grab *pg = (struct pointer_grab *)grab; + + pointer_move_workspace_grab_end(pg); + free(grab); + } +} + +static void +touch_nope_grab_down(struct weston_touch_grab *grab, uint32_t time, + int touch_id, wl_fixed_t sx, wl_fixed_t sy) +{ +} + +static void +touch_move_workspace_grab_up(struct weston_touch_grab *grab, uint32_t time, + int touch_id) +{ + struct touch_move_grab *tch_move_grab = (struct touch_move_grab *)grab; + + if (0 == touch_id) + tch_move_grab->is_active = 0; + + if (0 == grab->touch->num_tp) { + touch_move_workspace_grab_end(&tch_move_grab->base); + free(grab); + } +} + +static void +pointer_move_workspace_grab_cancel(struct weston_pointer_grab *grab) +{ + struct pointer_grab *pg = (struct pointer_grab *)grab; + + pointer_move_workspace_grab_end(pg); + free(grab); +} + +static void +touch_move_workspace_grab_frame(struct weston_touch_grab *grab) +{ +} + +static void +touch_move_workspace_grab_cancel(struct weston_touch_grab *grab) +{ + struct touch_grab *tg = (struct touch_grab *)grab; + + touch_move_workspace_grab_end(tg); + free(grab); +} + +static const struct weston_pointer_grab_interface pointer_move_grab_workspace_interface = { + pointer_noop_grab_focus, + pointer_move_grab_motion, + pointer_move_workspace_grab_button, + pointer_move_workspace_grab_cancel +}; + +static const struct weston_touch_grab_interface touch_move_grab_workspace_interface = { + touch_nope_grab_down, + touch_move_workspace_grab_up, + touch_move_grab_motion, + touch_move_workspace_grab_frame, + touch_move_workspace_grab_cancel +}; + +enum HMI_GRAB_DEVICE { + HMI_GRAB_DEVICE_NONE, + HMI_GRAB_DEVICE_POINTER, + HMI_GRAB_DEVICE_TOUCH +}; + +static enum HMI_GRAB_DEVICE +get_hmi_grab_device(struct weston_seat *seat, uint32_t serial) +{ + struct weston_pointer *pointer = seat->pointer; + struct weston_touch *touch = seat->touch; + + if (pointer && + pointer->focus && + pointer->button_count && + pointer->grab_serial == serial) + return HMI_GRAB_DEVICE_POINTER; + + if (touch && + touch->focus && + touch->grab_serial == serial) + return HMI_GRAB_DEVICE_TOUCH; + + return HMI_GRAB_DEVICE_NONE; +} + +static void +move_grab_init(struct move_grab* move, wl_fixed_t start_pos[2], + wl_fixed_t grab_pos[2], wl_fixed_t rgn[2][2], + struct wl_resource* resource) +{ + clock_gettime(CLOCK_MONOTONIC, &move->start_time); //FIXME + move->pre_time = move->start_time; + move->pos[0] = start_pos[0]; + move->pos[1] = start_pos[1]; + move->start_pos[0] = start_pos[0]; + move->start_pos[1] = start_pos[1]; + move->dst[0] = start_pos[0] - grab_pos[0]; + move->dst[1] = start_pos[1] - grab_pos[1]; + memcpy(move->rgn, rgn, sizeof(move->rgn)); +} + +static void +move_grab_init_workspace(struct move_grab* move, + wl_fixed_t grab_x, wl_fixed_t grab_y, + struct wl_resource *resource) +{ + struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource); + struct ivi_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer; + int32_t workspace_count = hmi_ctrl->workspace_count; + int32_t workspace_width = hmi_ctrl->workspace_background_layer.width; + int32_t layer_pos_x = 0; + int32_t layer_pos_y = 0; + wl_fixed_t start_pos[2] = {0}; + wl_fixed_t rgn[2][2] = {{0}}; + wl_fixed_t grab_pos[2] = { grab_x, grab_y }; + + ivi_controller_interface->layer_get_position(layer, &layer_pos_x, &layer_pos_y); + + start_pos[0] = wl_fixed_from_int(layer_pos_x); + start_pos[1] = wl_fixed_from_int(layer_pos_y); + + rgn[0][0] = wl_fixed_from_int(-workspace_width * (workspace_count - 1)); + + rgn[0][1] = wl_fixed_from_int(0); + rgn[1][0] = wl_fixed_from_int(0); + rgn[1][1] = wl_fixed_from_int(0); + + move_grab_init(move, start_pos, grab_pos, rgn, resource); +} + +static struct pointer_move_grab * +create_workspace_pointer_move(struct weston_pointer *pointer, + struct wl_resource* resource) +{ + struct pointer_move_grab *pnt_move_grab = + MEM_ALLOC(sizeof(*pnt_move_grab)); + + pnt_move_grab->base.resource = resource; + move_grab_init_workspace(&pnt_move_grab->move, pointer->grab_x, + pointer->grab_y, resource); + + return pnt_move_grab; +} + +static struct touch_move_grab * +create_workspace_touch_move(struct weston_touch *touch, + struct wl_resource* resource) +{ + struct touch_move_grab *tch_move_grab = + MEM_ALLOC(sizeof(*tch_move_grab)); + + tch_move_grab->base.resource = resource; + tch_move_grab->is_active = 1; + move_grab_init_workspace(&tch_move_grab->move, touch->grab_x, + touch->grab_y, resource); + + return tch_move_grab; +} + +static void +ivi_hmi_controller_workspace_control(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial) +{ + struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource); + struct ivi_layout_layer *layer = NULL; + struct pointer_move_grab *pnt_move_grab = NULL; + struct touch_move_grab *tch_move_grab = NULL; + struct weston_seat *seat = NULL; + struct weston_pointer *pointer; + struct weston_touch *touch; + + enum HMI_GRAB_DEVICE device; + + if (hmi_ctrl->workspace_count < 2) + return; + + seat = wl_resource_get_user_data(seat_resource); + device = get_hmi_grab_device(seat, serial); + + if (HMI_GRAB_DEVICE_POINTER != device && + HMI_GRAB_DEVICE_TOUCH != device) + return; + + layer = hmi_ctrl->workspace_layer.ivilayer; + + ivi_controller_interface->transition_move_layer_cancel(layer); + + switch (device) { + case HMI_GRAB_DEVICE_POINTER: + pointer = seat->pointer; + pnt_move_grab = create_workspace_pointer_move(pointer, + resource); + + pointer_grab_start(&pnt_move_grab->base, layer, + &pointer_move_grab_workspace_interface, + pointer); + break; + + case HMI_GRAB_DEVICE_TOUCH: + touch = seat->touch; + tch_move_grab = create_workspace_touch_move(touch, + resource); + + touch_grab_start(&tch_move_grab->base, layer, + &touch_move_grab_workspace_interface, + touch); + break; + + default: + break; + } +} + +/** + * Implementation of switch_mode + */ +static void +ivi_hmi_controller_switch_mode(struct wl_client *client, + struct wl_resource *resource, + uint32_t layout_mode) +{ + struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource); + + switch_mode(hmi_ctrl, layout_mode); +} + +/** + * Implementation of on/off displaying workspace and workspace background + * ivi_layers. + */ +static void +ivi_hmi_controller_home(struct wl_client *client, + struct wl_resource *resource, + uint32_t home) +{ + struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource); + uint32_t is_fade_in; + + if ((IVI_HMI_CONTROLLER_HOME_ON == home && + !hmi_ctrl->workspace_fade.is_fade_in) || + (IVI_HMI_CONTROLLER_HOME_OFF == home && + hmi_ctrl->workspace_fade.is_fade_in)) { + is_fade_in = !hmi_ctrl->workspace_fade.is_fade_in; + hmi_controller_fade_run(hmi_ctrl, is_fade_in, + &hmi_ctrl->workspace_fade); + } + + ivi_controller_interface->commit_changes(); +} + +/** + * binding ivi-hmi-controller implementation + */ +static const struct ivi_hmi_controller_interface ivi_hmi_controller_implementation = { + ivi_hmi_controller_UI_ready, + ivi_hmi_controller_workspace_control, + ivi_hmi_controller_switch_mode, + ivi_hmi_controller_home +}; + +static void +unbind_hmi_controller(struct wl_resource *resource) +{ +} + +static void +bind_hmi_controller(struct wl_client *client, + void *data, uint32_t version, uint32_t id) +{ + struct wl_resource *resource = NULL; + struct hmi_controller *hmi_ctrl = data; + + if (hmi_ctrl->user_interface != client) { + struct wl_resource *res = wl_client_get_object(client, 1); + wl_resource_post_error(res, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "hmi-controller failed: permission denied"); + return; + } + + resource = wl_resource_create( + client, &ivi_hmi_controller_interface, 1, id); + + wl_resource_set_implementation( + resource, &ivi_hmi_controller_implementation, + hmi_ctrl, unbind_hmi_controller); +} + +static void +handle_hmi_client_process_sigchld(struct weston_process *proc, int status) +{ + proc->pid = 0; +} + +static int32_t +initialize(struct hmi_controller *hmi_ctrl) +{ + struct config_command { + char *key; + uint32_t *dest; + }; + + struct weston_config *config = hmi_ctrl->compositor->config; + struct weston_config_section *section = NULL; + int result = 0; + int i = 0; + + const struct config_command uint_commands[] = { + { "background-id", &hmi_ctrl->ui_setting.background_id }, + { "panel-id", &hmi_ctrl->ui_setting.panel_id }, + { "tiling-id", &hmi_ctrl->ui_setting.tiling_id }, + { "sidebyside-id", &hmi_ctrl->ui_setting.sidebyside_id }, + { "fullscreen-id", &hmi_ctrl->ui_setting.fullscreen_id }, + { "random-id", &hmi_ctrl->ui_setting.random_id }, + { "home-id", &hmi_ctrl->ui_setting.home_id }, + { "workspace-background-id", &hmi_ctrl->ui_setting.workspace_background_id }, + { NULL, NULL } + }; + + section = weston_config_get_section(config, "ivi-shell", NULL, NULL); + + for (i = 0; -1 != result; ++i) { + const struct config_command *command = &uint_commands[i]; + + if (!command->key) + break; + + if (weston_config_section_get_uint( + section, command->key, command->dest, 0) != 0) + result = -1; + } + + if (-1 == result) { + weston_log("Failed to initialize hmi-controller\n"); + return 0; + } + + return 1; +} + +static void +launch_hmi_client_process(void *data) +{ + struct hmi_controller *hmi_ctrl = + (struct hmi_controller *)data; + + hmi_ctrl->user_interface = + weston_client_launch(hmi_ctrl->compositor, + &hmi_ctrl->process, + hmi_ctrl->hmi_setting->ivi_homescreen, + handle_hmi_client_process_sigchld); + + free(hmi_ctrl->hmi_setting->ivi_homescreen); +} + +/***************************************************************************** + * exported functions + ****************************************************************************/ +WL_EXPORT int +controller_module_init(struct weston_compositor *ec, + int *argc, char *argv[], + const struct ivi_controller_interface *interface, + size_t interface_version) +{ + struct hmi_controller *hmi_ctrl = NULL; + struct wl_event_loop *loop = NULL; + + if (interface_version < sizeof(struct ivi_controller_interface)) { + weston_log("ivi-shell: version mismatch of controller interface"); + return -1; + } + + ivi_controller_interface = interface; + + hmi_ctrl = hmi_controller_create(ec); + + if (!initialize(hmi_ctrl)) { + return -1; + } + + if (wl_global_create(ec->wl_display, + &ivi_hmi_controller_interface, 1, + hmi_ctrl, bind_hmi_controller) == NULL) { + return -1; + } + + loop = wl_display_get_event_loop(ec->wl_display); + wl_event_loop_add_idle(loop, launch_hmi_client_process, hmi_ctrl); + + return 0; +} diff --git a/ivi-shell/input-panel-ivi.c b/ivi-shell/input-panel-ivi.c new file mode 100644 index 0000000..51d2b8a --- /dev/null +++ b/ivi-shell/input-panel-ivi.c @@ -0,0 +1,397 @@ +/* + * Copyright © 2010-2012 Intel Corporation + * Copyright © 2011-2012 Collabora, Ltd. + * Copyright © 2013 Raspberry Pi Foundation + * + * 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 "ivi-shell.h" +#include "input-method-server-protocol.h" +#include "ivi-layout-private.h" +#include "shared/helpers.h" + +struct input_panel_surface { + struct wl_resource *resource; + struct wl_signal destroy_signal; + + struct ivi_shell *shell; + + struct wl_list link; + struct weston_surface *surface; + struct weston_view *view; + struct wl_listener surface_destroy_listener; + + struct weston_view_animation *anim; + + struct weston_output *output; + uint32_t panel; +}; + +static void +input_panel_slide_done(struct weston_view_animation *animation, void *data) +{ + struct input_panel_surface *ipsurf = data; + + ipsurf->anim = NULL; +} + +static void +show_input_panel_surface(struct input_panel_surface *ipsurf) +{ + struct ivi_shell *shell = ipsurf->shell; + struct weston_seat *seat; + struct weston_surface *focus; + float x, y; + + wl_list_for_each(seat, &shell->compositor->seat_list, link) { + struct weston_keyboard *keyboard = seat->keyboard; + + if (!keyboard || !keyboard->focus) + continue; + focus = weston_surface_get_main_surface(keyboard->focus); + ipsurf->output = focus->output; + x = ipsurf->output->x + (ipsurf->output->width - ipsurf->surface->width) / 2; + y = ipsurf->output->y + ipsurf->output->height - ipsurf->surface->height; + weston_view_set_position(ipsurf->view, x, y); + } + + wl_list_insert(&shell->input_panel_layer.view_list, + &ipsurf->view->layer_link); + weston_view_geometry_dirty(ipsurf->view); + weston_view_update_transform(ipsurf->view); + weston_surface_damage(ipsurf->surface); + + if (ipsurf->anim) + weston_view_animation_destroy(ipsurf->anim); + + ipsurf->anim = + weston_slide_run(ipsurf->view, + ipsurf->surface->height * 0.9, 0, + input_panel_slide_done, ipsurf); +} + +static void +show_input_panels(struct wl_listener *listener, void *data) +{ + struct ivi_shell *shell = + container_of(listener, struct ivi_shell, + show_input_panel_listener); + struct input_panel_surface *ipsurf, *next; + + shell->text_input.surface = (struct weston_surface*)data; + + if (shell->showing_input_panels) + return; + + shell->showing_input_panels = true; + + if (!shell->locked) + wl_list_insert(&shell->compositor->cursor_layer.link, + &shell->input_panel_layer.link); + + wl_list_for_each_safe(ipsurf, next, + &shell->input_panel.surfaces, link) { + if (ipsurf->surface->width == 0) + continue; + + show_input_panel_surface(ipsurf); + } +} + +static void +hide_input_panels(struct wl_listener *listener, void *data) +{ + struct ivi_shell *shell = + container_of(listener, struct ivi_shell, + hide_input_panel_listener); + struct weston_view *view, *next; + + if (!shell->showing_input_panels) + return; + + shell->showing_input_panels = false; + + if (!shell->locked) + wl_list_remove(&shell->input_panel_layer.link); + + wl_list_for_each_safe(view, next, + &shell->input_panel_layer.view_list, + layer_link) + weston_view_unmap(view); +} + +static void +update_input_panels(struct wl_listener *listener, void *data) +{ + struct ivi_shell *shell = + container_of(listener, struct ivi_shell, + update_input_panel_listener); + + memcpy(&shell->text_input.cursor_rectangle, data, sizeof(pixman_box32_t)); +} + +static void +input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy) +{ + struct input_panel_surface *ip_surface = surface->configure_private; + struct ivi_shell *shell = ip_surface->shell; + struct weston_view *view; + float x, y; + + if (surface->width == 0) + return; + + if (ip_surface->panel) { + view = get_default_view(shell->text_input.surface); + if (view == NULL) + return; + x = view->geometry.x + shell->text_input.cursor_rectangle.x2; + y = view->geometry.y + shell->text_input.cursor_rectangle.y2; + } else { + x = ip_surface->output->x + (ip_surface->output->width - surface->width) / 2; + y = ip_surface->output->y + ip_surface->output->height - surface->height; + } + + weston_view_set_position(ip_surface->view, x, y); + + if (!weston_surface_is_mapped(surface) && shell->showing_input_panels) + show_input_panel_surface(ip_surface); +} + +static void +destroy_input_panel_surface(struct input_panel_surface *input_panel_surface) +{ + wl_signal_emit(&input_panel_surface->destroy_signal, input_panel_surface); + + wl_list_remove(&input_panel_surface->surface_destroy_listener.link); + wl_list_remove(&input_panel_surface->link); + + input_panel_surface->surface->configure = NULL; + weston_view_destroy(input_panel_surface->view); + + free(input_panel_surface); +} + +static struct input_panel_surface * +get_input_panel_surface(struct weston_surface *surface) +{ + if (surface->configure == input_panel_configure) { + return surface->configure_private; + } else { + return NULL; + } +} + +static void +input_panel_handle_surface_destroy(struct wl_listener *listener, void *data) +{ + struct input_panel_surface *ipsurface = container_of(listener, + struct input_panel_surface, + surface_destroy_listener); + + if (ipsurface->resource) { + wl_resource_destroy(ipsurface->resource); + } else { + destroy_input_panel_surface(ipsurface); + } +} + +static struct input_panel_surface * +create_input_panel_surface(struct ivi_shell *shell, + struct weston_surface *surface) +{ + struct input_panel_surface *input_panel_surface; + + input_panel_surface = calloc(1, sizeof *input_panel_surface); + if (!input_panel_surface) + return NULL; + + surface->configure = input_panel_configure; + surface->configure_private = input_panel_surface; + + input_panel_surface->shell = shell; + + input_panel_surface->surface = surface; + input_panel_surface->view = weston_view_create(surface); + + wl_signal_init(&input_panel_surface->destroy_signal); + input_panel_surface->surface_destroy_listener.notify = input_panel_handle_surface_destroy; + wl_signal_add(&surface->destroy_signal, + &input_panel_surface->surface_destroy_listener); + + wl_list_init(&input_panel_surface->link); + + return input_panel_surface; +} + +static void +input_panel_surface_set_toplevel(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output_resource, + uint32_t position) +{ + struct input_panel_surface *input_panel_surface = + wl_resource_get_user_data(resource); + struct ivi_shell *shell = input_panel_surface->shell; + + wl_list_insert(&shell->input_panel.surfaces, + &input_panel_surface->link); + + input_panel_surface->output = wl_resource_get_user_data(output_resource); + input_panel_surface->panel = 0; +} + +static void +input_panel_surface_set_overlay_panel(struct wl_client *client, + struct wl_resource *resource) +{ + struct input_panel_surface *input_panel_surface = + wl_resource_get_user_data(resource); + struct ivi_shell *shell = input_panel_surface->shell; + + wl_list_insert(&shell->input_panel.surfaces, + &input_panel_surface->link); + + input_panel_surface->panel = 1; +} + +static const struct wl_input_panel_surface_interface input_panel_surface_implementation = { + input_panel_surface_set_toplevel, + input_panel_surface_set_overlay_panel +}; + +static void +destroy_input_panel_surface_resource(struct wl_resource *resource) +{ + struct input_panel_surface *ipsurf = + wl_resource_get_user_data(resource); + + destroy_input_panel_surface(ipsurf); +} + +static void +input_panel_get_input_panel_surface(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource) +{ + struct weston_surface *surface = + wl_resource_get_user_data(surface_resource); + struct ivi_shell *shell = wl_resource_get_user_data(resource); + struct input_panel_surface *ipsurf; + + if (get_input_panel_surface(surface)) { + wl_resource_post_error(surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "wl_input_panel::get_input_panel_surface already requested"); + return; + } + + ipsurf = create_input_panel_surface(shell, surface); + if (!ipsurf) { + wl_resource_post_error(surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "surface->configure already set"); + return; + } + + ipsurf->resource = + wl_resource_create(client, + &wl_input_panel_surface_interface, 1, id); + wl_resource_set_implementation(ipsurf->resource, + &input_panel_surface_implementation, + ipsurf, + destroy_input_panel_surface_resource); +} + +static const struct wl_input_panel_interface input_panel_implementation = { + input_panel_get_input_panel_surface +}; + +static void +unbind_input_panel(struct wl_resource *resource) +{ + struct ivi_shell *shell = wl_resource_get_user_data(resource); + + shell->input_panel.binding = NULL; +} + +static void +bind_input_panel(struct wl_client *client, + void *data, uint32_t version, uint32_t id) +{ + struct ivi_shell *shell = data; + struct wl_resource *resource; + + resource = wl_resource_create(client, + &wl_input_panel_interface, 1, id); + + if (shell->input_panel.binding == NULL) { + wl_resource_set_implementation(resource, + &input_panel_implementation, + shell, unbind_input_panel); + shell->input_panel.binding = resource; + return; + } + + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "interface object already bound"); +} + +void +input_panel_destroy(struct ivi_shell *shell) +{ + wl_list_remove(&shell->show_input_panel_listener.link); + wl_list_remove(&shell->hide_input_panel_listener.link); +} + +int +input_panel_setup(struct ivi_shell *shell) +{ + struct weston_compositor *ec = shell->compositor; + + shell->show_input_panel_listener.notify = show_input_panels; + wl_signal_add(&ec->show_input_panel_signal, + &shell->show_input_panel_listener); + shell->hide_input_panel_listener.notify = hide_input_panels; + wl_signal_add(&ec->hide_input_panel_signal, + &shell->hide_input_panel_listener); + shell->update_input_panel_listener.notify = update_input_panels; + wl_signal_add(&ec->update_input_panel_signal, + &shell->update_input_panel_listener); + + wl_list_init(&shell->input_panel.surfaces); + + if (wl_global_create(shell->compositor->wl_display, + &wl_input_panel_interface, 1, + shell, bind_input_panel) == NULL) + return -1; + + return 0; +} diff --git a/ivi-shell/ivi-layout-export.h b/ivi-shell/ivi-layout-export.h new file mode 100644 index 0000000..8a92009 --- /dev/null +++ b/ivi-shell/ivi-layout-export.h @@ -0,0 +1,813 @@ +/* + * Copyright (C) 2013 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. + */ + +/** + * The ivi-layout library supports API set of controlling properties of + * surface and layer which groups surfaces. An unique ID whose type is integer + * is required to create surface and layer. With the unique ID, surface and + * layer are identified to control them. The API set consists of APIs to control + * properties of surface and layers about followings, + * - visibility. + * - opacity. + * - clipping (x,y,width,height). + * - position and size of it to be displayed. + * - orientation per 90 degree. + * - add or remove surfaces to a layer. + * - order of surfaces/layers in layer/screen to be displayed. + * - commit to apply property changes. + * - notifications of property change. + * + * Management of surfaces and layers grouping these surfaces are common + * way in In-Vehicle Infotainment system, which integrate several domains + * in one system. A layer is allocated to a domain in order to control + * application surfaces grouped to the layer all together. + * + * This API and ABI follow following specifications. + * http://projects.genivi.org/wayland-ivi-extension/layer-manager-apis + */ + +#ifndef _IVI_LAYOUT_EXPORT_H_ +#define _IVI_LAYOUT_EXPORT_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "stdbool.h" +#include "compositor.h" + +#define IVI_SUCCEEDED (0) +#define IVI_FAILED (-1) + +struct ivi_layout_layer; +struct ivi_layout_screen; +struct ivi_layout_surface; + +struct ivi_layout_surface_properties +{ + wl_fixed_t opacity; + int32_t source_x; + int32_t source_y; + int32_t source_width; + int32_t source_height; + int32_t start_x; + int32_t start_y; + int32_t start_width; + int32_t start_height; + int32_t dest_x; + int32_t dest_y; + int32_t dest_width; + int32_t dest_height; + enum wl_output_transform orientation; + bool visibility; + int32_t transition_type; + uint32_t transition_duration; +}; + +struct ivi_layout_layer_properties +{ + wl_fixed_t opacity; + int32_t source_x; + int32_t source_y; + int32_t source_width; + int32_t source_height; + int32_t dest_x; + int32_t dest_y; + int32_t dest_width; + int32_t dest_height; + enum wl_output_transform orientation; + uint32_t visibility; + int32_t transition_type; + uint32_t transition_duration; + double start_alpha; + double end_alpha; + uint32_t is_fade_in; +}; + +enum ivi_layout_notification_mask { + IVI_NOTIFICATION_NONE = 0, + IVI_NOTIFICATION_OPACITY = (1 << 1), + IVI_NOTIFICATION_SOURCE_RECT = (1 << 2), + IVI_NOTIFICATION_DEST_RECT = (1 << 3), + IVI_NOTIFICATION_DIMENSION = (1 << 4), + IVI_NOTIFICATION_POSITION = (1 << 5), + IVI_NOTIFICATION_ORIENTATION = (1 << 6), + IVI_NOTIFICATION_VISIBILITY = (1 << 7), + IVI_NOTIFICATION_PIXELFORMAT = (1 << 8), + IVI_NOTIFICATION_ADD = (1 << 9), + IVI_NOTIFICATION_REMOVE = (1 << 10), + IVI_NOTIFICATION_CONFIGURE = (1 << 11), + IVI_NOTIFICATION_ALL = 0xFFFF +}; + +enum ivi_layout_transition_type{ + IVI_LAYOUT_TRANSITION_NONE, + IVI_LAYOUT_TRANSITION_VIEW_DEFAULT, + IVI_LAYOUT_TRANSITION_VIEW_DEST_RECT_ONLY, + IVI_LAYOUT_TRANSITION_VIEW_FADE_ONLY, + IVI_LAYOUT_TRANSITION_LAYER_FADE, + IVI_LAYOUT_TRANSITION_LAYER_MOVE, + IVI_LAYOUT_TRANSITION_LAYER_VIEW_ORDER, + IVI_LAYOUT_TRANSITION_VIEW_MOVE_RESIZE, + IVI_LAYOUT_TRANSITION_VIEW_RESIZE, + IVI_LAYOUT_TRANSITION_VIEW_FADE, + IVI_LAYOUT_TRANSITION_MAX, +}; + +typedef void (*layer_property_notification_func)( + struct ivi_layout_layer *ivilayer, + const struct ivi_layout_layer_properties *, + enum ivi_layout_notification_mask mask, + void *userdata); + +typedef void (*surface_property_notification_func)( + struct ivi_layout_surface *ivisurf, + const struct ivi_layout_surface_properties *, + enum ivi_layout_notification_mask mask, + void *userdata); + +typedef void (*layer_create_notification_func)( + struct ivi_layout_layer *ivilayer, + void *userdata); + +typedef void (*layer_remove_notification_func)( + struct ivi_layout_layer *ivilayer, + void *userdata); + +typedef void (*surface_create_notification_func)( + struct ivi_layout_surface *ivisurf, + void *userdata); + +typedef void (*surface_remove_notification_func)( + struct ivi_layout_surface *ivisurf, + void *userdata); + +typedef void (*surface_configure_notification_func)( + struct ivi_layout_surface *ivisurf, + void *userdata); + +typedef void (*ivi_controller_surface_content_callback)( + struct ivi_layout_surface *ivisurf, + int32_t content, + void *userdata); + +struct ivi_controller_interface { + + /** + * \brief Commit all changes and execute all enqueued commands since + * last commit. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*commit_changes)(void); + + /** + * surface controller interface + */ + + /** + * \brief register/unregister for notification when ivi_surface is created + */ + int32_t (*add_notification_create_surface)( + surface_create_notification_func callback, + void *userdata); + + void (*remove_notification_create_surface)( + surface_create_notification_func callback, + void *userdata); + + /** + * \brief register/unregister for notification when ivi_surface is removed + */ + int32_t (*add_notification_remove_surface)( + surface_remove_notification_func callback, + void *userdata); + + void (*remove_notification_remove_surface)( + surface_remove_notification_func callback, + void *userdata); + + /** + * \brief register/unregister for notification when ivi_surface is configured + */ + int32_t (*add_notification_configure_surface)( + surface_configure_notification_func callback, + void *userdata); + + void (*remove_notification_configure_surface)( + surface_configure_notification_func callback, + void *userdata); + + /** + * \brief Get all ivi_surfaces which are currently registered and managed + * by the services + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*get_surfaces)(int32_t *pLength, struct ivi_layout_surface ***ppArray); + + /** + * \brief get id of ivi_surface from ivi_layout_surface + * + * \return id of ivi_surface + */ + uint32_t (*get_id_of_surface)(struct ivi_layout_surface *ivisurf); + + /** + * \brief get ivi_layout_surface from id of ivi_surface + * + * \return (struct ivi_layout_surface *) + * if the method call was successful + * \return NULL if the method call was failed + */ + struct ivi_layout_surface * + (*get_surface_from_id)(uint32_t id_surface); + + /** + * \brief get ivi_layout_surface_properties from ivisurf + * + * \return (struct ivi_layout_surface_properties *) + * if the method call was successful + * \return NULL if the method call was failed + */ + const struct ivi_layout_surface_properties * + (*get_properties_of_surface)(struct ivi_layout_surface *ivisurf); + + /** + * \brief Get all Surfaces which are currently registered to a given + * layer and are managed by the services + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*get_surfaces_on_layer)(struct ivi_layout_layer *ivilayer, + int32_t *pLength, + struct ivi_layout_surface ***ppArray); + + /** + * \brief Set the visibility of a ivi_surface. + * + * If a surface is not visible it will not be rendered. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_set_visibility)(struct ivi_layout_surface *ivisurf, + bool newVisibility); + + /** + * \brief Get the visibility of a surface. + * + * If a surface is not visible it will not be rendered. + * + * \return true if surface is visible + * \return false if surface is invisible or the method call was failed + */ + bool (*surface_get_visibility)(struct ivi_layout_surface *ivisurf); + + /** + * \brief Set the opacity of a surface. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_set_opacity)(struct ivi_layout_surface *ivisurf, + wl_fixed_t opacity); + + /** + * \brief Get the opacity of a ivi_surface. + * + * \return opacity if the method call was successful + * \return wl_fixed_from_double(0.0) if the method call was failed + */ + wl_fixed_t (*surface_get_opacity)(struct ivi_layout_surface *ivisurf); + + /** + * \brief Set the area of a ivi_surface which should be used for the rendering. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_set_source_rectangle)(struct ivi_layout_surface *ivisurf, + int32_t x, int32_t y, + int32_t width, int32_t height); + + /** + * \brief Set the destination area of a ivi_surface within a ivi_layer + * for rendering. + * + * The surface will be scaled to this rectangle for rendering. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_set_destination_rectangle)(struct ivi_layout_surface *ivisurf, + int32_t x, int32_t y, + int32_t width, int32_t height); + + /** + * \brief Sets the horizontal and vertical position of the surface. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_set_position)(struct ivi_layout_surface *ivisurf, + int32_t dest_x, int32_t dest_y); + + /** + * \brief Get the horizontal and vertical position of the surface. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_get_position)(struct ivi_layout_surface *ivisurf, + int32_t *dest_x, int32_t *dest_y); + + /** + * \brief Set the horizontal and vertical dimension of the surface. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_set_dimension)(struct ivi_layout_surface *ivisurf, + int32_t dest_width, int32_t dest_height); + + /** + * \brief Get the horizontal and vertical dimension of the surface. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_get_dimension)(struct ivi_layout_surface *ivisurf, + int32_t *dest_width, int32_t *dest_height); + + /** + * \brief Sets the orientation of a ivi_surface. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_set_orientation)(struct ivi_layout_surface *ivisurf, + enum wl_output_transform orientation); + + /** + * \brief Gets the orientation of a surface. + * + * \return (enum wl_output_transform) + * if the method call was successful + * \return WL_OUTPUT_TRANSFORM_NORMAL if the method call was failed + */ + enum wl_output_transform + (*surface_get_orientation)(struct ivi_layout_surface *ivisurf); + + /** + * \brief Set an observer callback for ivi_surface content status change. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_set_content_observer)( + struct ivi_layout_surface *ivisurf, + ivi_controller_surface_content_callback callback, + void* userdata); + + /** + * \brief register for notification on property changes of ivi_surface + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*surface_add_notification)(struct ivi_layout_surface *ivisurf, + surface_property_notification_func callback, + void *userdata); + + /** + * \brief remove notification on property changes of ivi_surface + */ + void (*surface_remove_notification)(struct ivi_layout_surface *ivisurf); + + /** + * \brief get weston_surface of ivi_surface + */ + struct weston_surface * + (*surface_get_weston_surface)(struct ivi_layout_surface *ivisurf); + + /** + * \brief set type of transition animation + */ + int32_t (*surface_set_transition)(struct ivi_layout_surface *ivisurf, + enum ivi_layout_transition_type type, + uint32_t duration); + + /** + * \brief set duration of transition animation + */ + int32_t (*surface_set_transition_duration)( + struct ivi_layout_surface *ivisurf, + uint32_t duration); + + /** + * layer controller interface + */ + + /** + * \brief register/unregister for notification when ivi_layer is created + */ + int32_t (*add_notification_create_layer)( + layer_create_notification_func callback, + void *userdata); + + void (*remove_notification_create_layer)( + layer_create_notification_func callback, + void *userdata); + + /** + * \brief register/unregister for notification when ivi_layer is removed + */ + int32_t (*add_notification_remove_layer)( + layer_remove_notification_func callback, + void *userdata); + + void (*remove_notification_remove_layer)( + layer_remove_notification_func callback, + void *userdata); + + /** + * \brief Create a ivi_layer which should be managed by the service + * + * \return (struct ivi_layout_layer *) + * if the method call was successful + * \return NULL if the method call was failed + */ + struct ivi_layout_layer * + (*layer_create_with_dimension)(uint32_t id_layer, + int32_t width, int32_t height); + + /** + * \brief Removes a ivi_layer which is currently managed by the service + */ + void (*layer_destroy)(struct ivi_layout_layer *ivilayer); + + /** + * \brief Get all ivi_layers which are currently registered and managed + * by the services + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*get_layers)(int32_t *pLength, struct ivi_layout_layer ***ppArray); + + /** + * \brief get id of ivi_layer from ivi_layout_layer + * + * + * \return id of ivi_layer + */ + uint32_t (*get_id_of_layer)(struct ivi_layout_layer *ivilayer); + + /** + * \brief get ivi_layout_layer from id of layer + * + * \return (struct ivi_layout_layer *) + * if the method call was successful + * \return NULL if the method call was failed + */ + struct ivi_layout_layer * (*get_layer_from_id)(uint32_t id_layer); + + /** + * \brief Get the ivi_layer properties + * + * \return (const struct ivi_layout_layer_properties *) + * if the method call was successful + * \return NULL if the method call was failed + */ + const struct ivi_layout_layer_properties * + (*get_properties_of_layer)(struct ivi_layout_layer *ivilayer); + + /** + * \brief Get all ivi_ayers under the given ivi_surface + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*get_layers_under_surface)(struct ivi_layout_surface *ivisurf, + int32_t *pLength, + struct ivi_layout_layer ***ppArray); + + /** + * \brief Get all Layers of the given screen + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*get_layers_on_screen)(struct ivi_layout_screen *iviscrn, + int32_t *pLength, + struct ivi_layout_layer ***ppArray); + + /** + * \brief Set the visibility of a ivi_layer. If a ivi_layer is not visible, + * the ivi_layer and its ivi_surfaces will not be rendered. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_set_visibility)(struct ivi_layout_layer *ivilayer, + bool newVisibility); + + /** + * \brief Get the visibility of a layer. If a layer is not visible, + * the layer and its surfaces will not be rendered. + * + * \return true if layer is visible + * \return false if layer is invisible or the method call was failed + */ + bool (*layer_get_visibility)(struct ivi_layout_layer *ivilayer); + + /** + * \brief Set the opacity of a ivi_layer. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_set_opacity)(struct ivi_layout_layer *ivilayer, + wl_fixed_t opacity); + + /** + * \brief Get the opacity of a ivi_layer. + * + * \return opacity if the method call was successful + * \return wl_fixed_from_double(0.0) if the method call was failed + */ + wl_fixed_t (*layer_get_opacity)(struct ivi_layout_layer *ivilayer); + + /** + * \brief Set the area of a ivi_layer which should be used for the rendering. + * + * Only this part will be visible. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_set_source_rectangle)(struct ivi_layout_layer *ivilayer, + int32_t x, int32_t y, + int32_t width, int32_t height); + + /** + * \brief Set the destination area on the display for a ivi_layer. + * + * The ivi_layer will be scaled and positioned to this rectangle + * for rendering + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_set_destination_rectangle)(struct ivi_layout_layer *ivilayer, + int32_t x, int32_t y, + int32_t width, int32_t height); + + /** + * \brief Sets the horizontal and vertical position of the ivi_layer. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_set_position)(struct ivi_layout_layer *ivilayer, + int32_t dest_x, int32_t dest_y); + + /** + * \brief Get the horizontal and vertical position of the ivi_layer. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_get_position)(struct ivi_layout_layer *ivilayer, + int32_t *dest_x, int32_t *dest_y); + + /** + * \brief Set the horizontal and vertical dimension of the layer. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_set_dimension)(struct ivi_layout_layer *ivilayer, + int32_t dest_width, int32_t dest_height); + + /** + * \brief Get the horizontal and vertical dimension of the layer. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_get_dimension)(struct ivi_layout_layer *ivilayer, + int32_t *dest_width, int32_t *dest_height); + + /** + * \brief Sets the orientation of a ivi_layer. + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_set_orientation)(struct ivi_layout_layer *ivilayer, + enum wl_output_transform orientation); + + /** + * \brief Gets the orientation of a layer. + * + * \return (enum wl_output_transform) + * if the method call was successful + * \return WL_OUTPUT_TRANSFORM_NORMAL if the method call was failed + */ + enum wl_output_transform + (*layer_get_orientation)(struct ivi_layout_layer *ivilayer); + + /** + * \brief Add a ivi_surface to a ivi_layer which is currently managed by the service + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_add_surface)(struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface *addsurf); + + /** + * \brief Removes a surface from a layer which is currently managed by the service + */ + void (*layer_remove_surface)(struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface *remsurf); + + /** + * \brief Sets render order of ivi_surfaces within a ivi_layer + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_set_render_order)(struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface **pSurface, + int32_t number); + + /** + * \brief register for notification on property changes of ivi_layer + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*layer_add_notification)(struct ivi_layout_layer *ivilayer, + layer_property_notification_func callback, + void *userdata); + + /** + * \brief remove notification on property changes of ivi_layer + */ + void (*layer_remove_notification)(struct ivi_layout_layer *ivilayer); + + /** + * \brief set type of transition animation + */ + int32_t (*layer_set_transition)(struct ivi_layout_layer *ivilayer, + enum ivi_layout_transition_type type, + uint32_t duration); + + /** + * screen controller interface + */ + + /** + * \brief get ivi_layout_screen from id of ivi_screen + * + * \return (struct ivi_layout_screen *) + * if the method call was successful + * \return NULL if the method call was failed + */ + struct ivi_layout_screen * + (*get_screen_from_id)(uint32_t id_screen); + + /** + * \brief Get the screen resolution of a specific ivi_screen + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*get_screen_resolution)(struct ivi_layout_screen *iviscrn, + int32_t *pWidth, + int32_t *pHeight); + + /** + * \brief Get the ivi_screens + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*get_screens)(int32_t *pLength, struct ivi_layout_screen ***ppArray); + + /** + * \brief Get the ivi_screens under the given ivi_layer + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*get_screens_under_layer)(struct ivi_layout_layer *ivilayer, + int32_t *pLength, + struct ivi_layout_screen ***ppArray); + + /** + * \brief Add a ivi_layer to a ivi_screen which is currently managed + * by the service + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*screen_add_layer)(struct ivi_layout_screen *iviscrn, + struct ivi_layout_layer *addlayer); + + /** + * \brief Sets render order of ivi_layers on a ivi_screen + * + * \return IVI_SUCCEEDED if the method call was successful + * \return IVI_FAILED if the method call was failed + */ + int32_t (*screen_set_render_order)(struct ivi_layout_screen *iviscrn, + struct ivi_layout_layer **pLayer, + const int32_t number); + + /** + * \brief get weston_output from ivi_layout_screen. + * + * \return (struct weston_output *) + * if the method call was successful + * \return NULL if the method call was failed + */ + struct weston_output *(*screen_get_output)(struct ivi_layout_screen *); + + + /** + * transision animation for layer + */ + void (*transition_move_layer_cancel)(struct ivi_layout_layer *layer); + int32_t (*layer_set_fade_info)(struct ivi_layout_layer* ivilayer, + uint32_t is_fade_in, + double start_alpha, double end_alpha); + + /** + * surface content dumping for debugging + */ + int32_t (*surface_get_size)(struct ivi_layout_surface *ivisurf, + int32_t *width, int32_t *height, + int32_t *stride); + + int32_t (*surface_dump)(struct weston_surface *surface, + void *target, size_t size, + int32_t x, int32_t y, + int32_t width, int32_t height); + + /** + * remove notification by callback on property changes of ivi_surface + */ + void (*surface_remove_notification_by_callback)(struct ivi_layout_surface *ivisurf, + surface_property_notification_func callback, + void *userdata); + + /** + * \brief remove notification by callback on property changes of ivi_layer + */ + void (*layer_remove_notification_by_callback)(struct ivi_layout_layer *ivilayer, + layer_property_notification_func callback, + void *userdata); + + /** + * \brief get id of ivi_screen from ivi_layout_screen + * + * + * \return id of ivi_screen + */ + uint32_t (*get_id_of_screen)(struct ivi_layout_screen *iviscrn); +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _IVI_LAYOUT_EXPORT_H_ */ diff --git a/ivi-shell/ivi-layout-private.h b/ivi-shell/ivi-layout-private.h new file mode 100644 index 0000000..074d598 --- /dev/null +++ b/ivi-shell/ivi-layout-private.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2014 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 _ivi_layout_PRIVATE_H_ +#define _ivi_layout_PRIVATE_H_ + +#include "compositor.h" +#include "ivi-layout-export.h" + +struct ivi_layout_surface { + struct wl_list link; + struct wl_signal property_changed; + struct wl_list layer_list; + int32_t update_count; + uint32_t id_surface; + + struct ivi_layout *layout; + struct weston_surface *surface; + + struct weston_transform transform; + + struct ivi_layout_surface_properties prop; + uint32_t event_mask; + + struct { + struct ivi_layout_surface_properties prop; + struct wl_list link; + } pending; + + struct { + struct wl_list link; + struct wl_list layer_list; + } order; + + struct { + ivi_controller_surface_content_callback callback; + void *userdata; + } content_observer; + + struct wl_signal configured; +}; + +struct ivi_layout_layer { + struct wl_list link; + struct wl_signal property_changed; + struct wl_list screen_list; + struct wl_list link_to_surface; + uint32_t id_layer; + + struct ivi_layout *layout; + + struct ivi_layout_layer_properties prop; + uint32_t event_mask; + + struct { + struct ivi_layout_layer_properties prop; + struct wl_list surface_list; + struct wl_list link; + } pending; + + struct { + int dirty; + struct wl_list surface_list; + struct wl_list link; + } order; + + int32_t ref_count; +}; + +struct ivi_layout { + struct weston_compositor *compositor; + + struct wl_list surface_list; + struct wl_list layer_list; + struct wl_list screen_list; + + struct { + struct wl_signal created; + struct wl_signal removed; + } layer_notification; + + struct { + struct wl_signal created; + struct wl_signal removed; + struct wl_signal configure_changed; + } surface_notification; + + struct weston_layer layout_layer; + struct wl_signal warning_signal; + + struct ivi_layout_transition_set *transitions; + struct wl_list pending_transition_list; +}; + +struct ivi_layout *get_instance(void); + +struct ivi_layout_transition; + +struct ivi_layout_transition_set { + struct wl_event_source *event_source; + struct wl_list transition_list; +}; + +typedef void (*ivi_layout_transition_destroy_user_func)(void *user_data); + +struct ivi_layout_transition_set * +ivi_layout_transition_set_create(struct weston_compositor *ec); + +void +ivi_layout_transition_move_resize_view(struct ivi_layout_surface *surface, + int32_t dest_x, int32_t dest_y, + int32_t dest_width, int32_t dest_height, + uint32_t duration); + +void +ivi_layout_transition_visibility_on(struct ivi_layout_surface *surface, + uint32_t duration); + +void +ivi_layout_transition_visibility_off(struct ivi_layout_surface *surface, + uint32_t duration); + + +void +ivi_layout_transition_move_layer(struct ivi_layout_layer *layer, + int32_t dest_x, int32_t dest_y, + uint32_t duration); + +void +ivi_layout_transition_fade_layer(struct ivi_layout_layer *layer, + uint32_t is_fade_in, + double start_alpha, double end_alpha, + void *user_data, + ivi_layout_transition_destroy_user_func destroy_func, + uint32_t duration); + +int32_t +is_surface_transition(struct ivi_layout_surface *surface); + +/** + * methods of interaction between ivi-shell with ivi-layout + */ +struct weston_view * +ivi_layout_get_weston_view(struct ivi_layout_surface *surface); +void +ivi_layout_surface_configure(struct ivi_layout_surface *ivisurf, + int32_t width, int32_t height); +struct ivi_layout_surface* +ivi_layout_surface_create(struct weston_surface *wl_surface, + uint32_t id_surface); +void +ivi_layout_init_with_compositor(struct weston_compositor *ec); +int32_t +ivi_layout_surface_get_dimension(struct ivi_layout_surface *ivisurf, + int32_t *dest_width, int32_t *dest_height); +void +ivi_layout_surface_add_configured_listener(struct ivi_layout_surface* ivisurf, + struct wl_listener* listener); +/** + * methods of interaction between transition animation with ivi-layout + */ +int32_t +ivi_layout_commit_changes(void); +uint32_t +ivi_layout_get_id_of_surface(struct ivi_layout_surface *ivisurf); +int32_t +ivi_layout_surface_set_destination_rectangle(struct ivi_layout_surface *ivisurf, + int32_t x, int32_t y, + int32_t width, int32_t height); +int32_t +ivi_layout_surface_set_opacity(struct ivi_layout_surface *ivisurf, + wl_fixed_t opacity); +wl_fixed_t +ivi_layout_surface_get_opacity(struct ivi_layout_surface *ivisurf); +int32_t +ivi_layout_surface_set_visibility(struct ivi_layout_surface *ivisurf, + bool newVisibility); +bool +ivi_layout_surface_get_visibility(struct ivi_layout_surface *ivisurf); +struct ivi_layout_surface * +ivi_layout_get_surface_from_id(uint32_t id_surface); +int32_t +ivi_layout_layer_set_opacity(struct ivi_layout_layer *ivilayer, + wl_fixed_t opacity); +wl_fixed_t +ivi_layout_layer_get_opacity(struct ivi_layout_layer *ivilayer); +int32_t +ivi_layout_layer_set_visibility(struct ivi_layout_layer *ivilayer, + bool newVisibility); +int32_t +ivi_layout_layer_set_position(struct ivi_layout_layer *ivilayer, + int32_t dest_x, int32_t dest_y); +int32_t +ivi_layout_layer_get_position(struct ivi_layout_layer *ivilayer, + int32_t *dest_x, int32_t *dest_y); +int32_t +ivi_layout_layer_set_render_order(struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface **pSurface, + int32_t number); +void +ivi_layout_transition_move_layer_cancel(struct ivi_layout_layer *layer); +int +load_controller_modules(struct weston_compositor *compositor, const char *modules, + int *argc, char *argv[]); +void +ivi_layout_surface_destroy(struct ivi_layout_surface *ivisurf); +#endif diff --git a/ivi-shell/ivi-layout-transition.c b/ivi-shell/ivi-layout-transition.c new file mode 100644 index 0000000..d12a8f4 --- /dev/null +++ b/ivi-shell/ivi-layout-transition.c @@ -0,0 +1,871 @@ +/* + * Copyright (C) 2014 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 + +#include "ivi-layout-export.h" +#include "ivi-layout-private.h" + +struct ivi_layout_transition; + +typedef void (*ivi_layout_transition_frame_func)( + struct ivi_layout_transition *transition); +typedef void (*ivi_layout_transition_destroy_func)( + struct ivi_layout_transition *transition); +typedef int32_t (*ivi_layout_is_transition_func)(void *private_data, void *id); + +struct ivi_layout_transition { + enum ivi_layout_transition_type type; + void *private_data; + void *user_data; + + uint32_t time_start; + uint32_t time_duration; + uint32_t time_elapsed; + uint32_t is_done; + ivi_layout_is_transition_func is_transition_func; + ivi_layout_transition_frame_func frame_func; + ivi_layout_transition_destroy_func destroy_func; +}; + +struct transition_node { + struct ivi_layout_transition *transition; + struct wl_list link; +}; + +static void layout_transition_destroy(struct ivi_layout_transition *transition); + +static struct ivi_layout_transition * +get_transition_from_type_and_id(enum ivi_layout_transition_type type, + void *id_data) +{ + struct ivi_layout *layout = get_instance(); + struct transition_node *node; + struct ivi_layout_transition *tran; + + wl_list_for_each(node, &layout->transitions->transition_list, link) { + tran = node->transition; + + if (tran->type == type && + tran->is_transition_func(tran->private_data, id_data)) + return tran; + } + + return NULL; +} + +int32_t +is_surface_transition(struct ivi_layout_surface *surface) +{ + struct ivi_layout *layout = get_instance(); + struct transition_node *node; + struct ivi_layout_transition *tran; + + wl_list_for_each(node, &layout->transitions->transition_list, link) { + tran = node->transition; + + if ((tran->type == IVI_LAYOUT_TRANSITION_VIEW_MOVE_RESIZE || + tran->type == IVI_LAYOUT_TRANSITION_VIEW_RESIZE) && + tran->is_transition_func(tran->private_data, surface)) + return 1; + } + + return 0; +} + +static void +tick_transition(struct ivi_layout_transition *transition, uint32_t timestamp) +{ + const double t = timestamp - transition->time_start; + + if (transition->time_duration <= t) { + transition->time_elapsed = transition->time_duration; + transition->is_done = 1; + } else { + transition->time_elapsed = t; + } +} + +static float time_to_nowpos(struct ivi_layout_transition *transition) +{ + return sin((float)transition->time_elapsed / + (float)transition->time_duration * M_PI_2); +} + +static void +do_transition_frame(struct ivi_layout_transition *transition, + uint32_t timestamp) +{ + if (0 == transition->time_start) + transition->time_start = timestamp; + + tick_transition(transition, timestamp); + transition->frame_func(transition); + + if (transition->is_done) + layout_transition_destroy(transition); +} + +static int32_t +layout_transition_frame(void *data) +{ + struct ivi_layout_transition_set *transitions = data; + uint32_t fps = 30; + struct timespec timestamp = {}; + uint32_t msec = 0; + struct transition_node *node = NULL; + struct transition_node *next = NULL; + + if (wl_list_empty(&transitions->transition_list)) { + wl_event_source_timer_update(transitions->event_source, 0); + return 1; + } + + wl_event_source_timer_update(transitions->event_source, 1000 / fps); + + clock_gettime(CLOCK_MONOTONIC, ×tamp);/* FIXME */ + msec = (1e+3 * timestamp.tv_sec + 1e-6 * timestamp.tv_nsec); + + wl_list_for_each_safe(node, next, &transitions->transition_list, link) { + do_transition_frame(node->transition, msec); + } + + ivi_layout_commit_changes(); + return 1; +} + +struct ivi_layout_transition_set * +ivi_layout_transition_set_create(struct weston_compositor *ec) +{ + struct ivi_layout_transition_set *transitions; + struct wl_event_loop *loop; + + transitions = malloc(sizeof(*transitions)); + if (transitions == NULL) { + weston_log("%s: memory allocation fails\n", __func__); + return NULL; + } + + wl_list_init(&transitions->transition_list); + + loop = wl_display_get_event_loop(ec->wl_display); + transitions->event_source = + wl_event_loop_add_timer(loop, layout_transition_frame, + transitions); + + return transitions; +} + +static void +layout_transition_register(struct ivi_layout_transition *trans) +{ + struct ivi_layout *layout = get_instance(); + struct transition_node *node; + + node = malloc(sizeof(*node)); + if (node == NULL) { + weston_log("%s: memory allocation fails\n", __func__); + return; + } + + node->transition = trans; + wl_list_insert(&layout->pending_transition_list, &node->link); +} + +static void +remove_transition(struct ivi_layout *layout, + struct ivi_layout_transition *trans) +{ + struct transition_node *node; + struct transition_node *next; + + wl_list_for_each_safe(node, next, + &layout->transitions->transition_list, link) { + if (node->transition == trans) { + wl_list_remove(&node->link); + free(node); + return; + } + } + + wl_list_for_each_safe(node, next, + &layout->pending_transition_list, link) { + if (node->transition == trans) { + wl_list_remove(&node->link); + free(node); + return; + } + } +} + +static void +layout_transition_destroy(struct ivi_layout_transition *transition) +{ + struct ivi_layout *layout = get_instance(); + + remove_transition(layout, transition); + if (transition->destroy_func) + transition->destroy_func(transition); + free(transition); +} + +static struct ivi_layout_transition * +create_layout_transition(void) +{ + struct ivi_layout_transition *transition = malloc(sizeof(*transition)); + + if (transition == NULL) { + weston_log("%s: memory allocation fails\n", __func__); + return NULL; + } + + transition->type = IVI_LAYOUT_TRANSITION_MAX; + transition->time_start = 0; + transition->time_duration = 300; /* 300ms */ + transition->time_elapsed = 0; + + transition->is_done = 0; + + transition->private_data = NULL; + transition->user_data = NULL; + + transition->frame_func = NULL; + transition->destroy_func = NULL; + + return transition; +} + +/* move and resize view transition */ + +struct move_resize_view_data { + struct ivi_layout_surface *surface; + int32_t start_x; + int32_t start_y; + int32_t end_x; + int32_t end_y; + int32_t start_width; + int32_t start_height; + int32_t end_width; + int32_t end_height; +}; + +static void +transition_move_resize_view_destroy(struct ivi_layout_transition *transition) +{ + struct move_resize_view_data *data = + (struct move_resize_view_data *)transition->private_data; + struct ivi_layout_surface *layout_surface = data->surface; + + wl_signal_emit(&layout_surface->configured, layout_surface); + + if (transition->private_data) { + free(transition->private_data); + transition->private_data = NULL; + } +} + +static void +transition_move_resize_view_user_frame(struct ivi_layout_transition *transition) +{ + struct move_resize_view_data *mrv = transition->private_data; + const double current = time_to_nowpos(transition); + + const int32_t destx = mrv->start_x + + (mrv->end_x - mrv->start_x) * current; + + const int32_t desty = mrv->start_y + + (mrv->end_y - mrv->start_y) * current; + + const int32_t dest_width = mrv->start_width + + (mrv->end_width - mrv->start_width) * current; + + const int32_t dest_height = mrv->start_height + + (mrv->end_height - mrv->start_height) * current; + + ivi_layout_surface_set_destination_rectangle(mrv->surface, + destx, desty, + dest_width, dest_height); +} + +static int32_t +is_transition_move_resize_view_func(struct move_resize_view_data *data, + struct ivi_layout_surface *view) +{ + return data->surface == view; +} + +static struct ivi_layout_transition * +create_move_resize_view_transition( + struct ivi_layout_surface *surface, + int32_t start_x, int32_t start_y, + int32_t end_x, int32_t end_y, + int32_t start_width, int32_t start_height, + int32_t end_width, int32_t end_height, + ivi_layout_transition_frame_func frame_func, + ivi_layout_transition_destroy_func destroy_func, + uint32_t duration) +{ + struct ivi_layout_transition *transition; + struct move_resize_view_data *data; + + transition = create_layout_transition(); + if (transition == NULL) + return NULL; + + data = malloc(sizeof(*data)); + if (data == NULL) { + weston_log("%s: memory allocation fails\n", __func__); + return NULL; + } + + transition->type = IVI_LAYOUT_TRANSITION_VIEW_MOVE_RESIZE; + transition->is_transition_func = (ivi_layout_is_transition_func)is_transition_move_resize_view_func; + + transition->frame_func = frame_func; + transition->destroy_func = destroy_func; + transition->private_data = data; + + if (duration != 0) + transition->time_duration = duration; + + data->surface = surface; + data->start_x = start_x; + data->start_y = start_y; + data->end_x = end_x; + data->end_y = end_y; + + data->start_width = start_width; + data->start_height = start_height; + data->end_width = end_width; + data->end_height = end_height; + + return transition; +} + +void +ivi_layout_transition_move_resize_view(struct ivi_layout_surface *surface, + int32_t dest_x, int32_t dest_y, + int32_t dest_width, int32_t dest_height, + uint32_t duration) +{ + struct ivi_layout_transition *transition; + int32_t start_pos[2] = { + surface->pending.prop.start_x, + surface->pending.prop.start_y + }; + + int32_t start_size[2] = { + surface->pending.prop.start_width, + surface->pending.prop.start_height + }; + + transition = get_transition_from_type_and_id( + IVI_LAYOUT_TRANSITION_VIEW_MOVE_RESIZE, + surface); + if (transition) { + struct move_resize_view_data *data = transition->private_data; + transition->time_start = 0; + transition->time_duration = duration; + + data->start_x = start_pos[0]; + data->start_y = start_pos[1]; + data->end_x = dest_x; + data->end_y = dest_y; + + data->start_width = start_size[0]; + data->start_height = start_size[1]; + data->end_width = dest_width; + data->end_height = dest_height; + return; + } + + transition = create_move_resize_view_transition( + surface, + start_pos[0], start_pos[1], + dest_x, dest_y, + start_size[0], start_size[1], + dest_width, dest_height, + transition_move_resize_view_user_frame, + transition_move_resize_view_destroy, + duration); + + layout_transition_register(transition); +} + +/* fade transition */ +struct fade_view_data { + struct ivi_layout_surface *surface; + double start_alpha; + double end_alpha; +}; + +struct store_alpha{ + double alpha; +}; + +static void +fade_view_user_frame(struct ivi_layout_transition *transition) +{ + struct fade_view_data *fade = transition->private_data; + struct ivi_layout_surface *surface = fade->surface; + + const double current = time_to_nowpos(transition); + const double alpha = fade->start_alpha + + (fade->end_alpha - fade->start_alpha) * current; + + ivi_layout_surface_set_opacity(surface, wl_fixed_from_double(alpha)); + ivi_layout_surface_set_visibility(surface, true); +} + +static int32_t +is_transition_fade_view_func(struct fade_view_data *data, + struct ivi_layout_surface *view) +{ + return data->surface == view; +} + +static struct ivi_layout_transition * +create_fade_view_transition( + struct ivi_layout_surface *surface, + double start_alpha, double end_alpha, + ivi_layout_transition_frame_func frame_func, + void *user_data, + ivi_layout_transition_destroy_func destroy_func, + uint32_t duration) +{ + struct ivi_layout_transition *transition; + struct fade_view_data *data; + + transition = create_layout_transition(); + if (transition == NULL) + return NULL; + + data = malloc(sizeof(*data)); + if (data == NULL) { + weston_log("%s: memory allocation fails\n", __func__); + return NULL; + } + + transition->type = IVI_LAYOUT_TRANSITION_VIEW_FADE; + transition->is_transition_func = (ivi_layout_is_transition_func)is_transition_fade_view_func; + + transition->user_data = user_data; + transition->private_data = data; + transition->frame_func = frame_func; + transition->destroy_func = destroy_func; + + if (duration != 0) + transition->time_duration = duration; + + data->surface = surface; + data->start_alpha = start_alpha; + data->end_alpha = end_alpha; + + return transition; +} + +static void +create_visibility_transition(struct ivi_layout_surface *surface, + double start_alpha, + double dest_alpha, + void *user_data, + ivi_layout_transition_destroy_func destroy_func, + uint32_t duration) +{ + struct ivi_layout_transition *transition = NULL; + + transition = create_fade_view_transition( + surface, + start_alpha, dest_alpha, + fade_view_user_frame, + user_data, + destroy_func, + duration); + + layout_transition_register(transition); +} + +static void +visibility_on_transition_destroy(struct ivi_layout_transition *transition) +{ + struct fade_view_data *data = transition->private_data; + struct store_alpha *user_data = transition->user_data; + + ivi_layout_surface_set_visibility(data->surface, true); + + free(data); + transition->private_data = NULL; + + free(user_data); + transition->user_data = NULL; +} + +void +ivi_layout_transition_visibility_on(struct ivi_layout_surface *surface, + uint32_t duration) +{ + struct ivi_layout_transition *transition; + bool is_visible = ivi_layout_surface_get_visibility(surface); + wl_fixed_t dest_alpha = ivi_layout_surface_get_opacity(surface); + struct store_alpha *user_data = NULL; + wl_fixed_t start_alpha = 0.0; + struct fade_view_data *data = NULL; + + transition = get_transition_from_type_and_id( + IVI_LAYOUT_TRANSITION_VIEW_FADE, + surface); + if (transition) { + start_alpha = ivi_layout_surface_get_opacity(surface); + user_data = transition->user_data; + data = transition->private_data; + + transition->time_start = 0; + transition->time_duration = duration; + transition->destroy_func = visibility_on_transition_destroy; + + data->start_alpha = wl_fixed_to_double(start_alpha); + data->end_alpha = user_data->alpha; + return; + } + + if (is_visible) + return; + + user_data = malloc(sizeof(*user_data)); + if (user_data == NULL) { + weston_log("%s: memory allocation fails\n", __func__); + return; + } + + user_data->alpha = wl_fixed_to_double(dest_alpha); + + create_visibility_transition(surface, + 0.0, // start_alpha + wl_fixed_to_double(dest_alpha), + user_data, + visibility_on_transition_destroy, + duration); +} + +static void +visibility_off_transition_destroy(struct ivi_layout_transition *transition) +{ + struct fade_view_data *data = transition->private_data; + struct store_alpha *user_data = transition->user_data; + + ivi_layout_surface_set_visibility(data->surface, false); + + ivi_layout_surface_set_opacity(data->surface, + wl_fixed_from_double(user_data->alpha)); + + free(data); + transition->private_data = NULL; + + free(user_data); + transition->user_data= NULL; +} + +void +ivi_layout_transition_visibility_off(struct ivi_layout_surface *surface, + uint32_t duration) +{ + struct ivi_layout_transition *transition; + wl_fixed_t start_alpha = ivi_layout_surface_get_opacity(surface); + struct store_alpha* user_data = NULL; + struct fade_view_data* data = NULL; + + transition = + get_transition_from_type_and_id(IVI_LAYOUT_TRANSITION_VIEW_FADE, + surface); + if (transition) { + data = transition->private_data; + + transition->time_start = 0; + transition->time_duration = duration; + transition->destroy_func = visibility_off_transition_destroy; + + data->start_alpha = wl_fixed_to_double(start_alpha); + data->end_alpha = 0; + return; + } + + user_data = malloc(sizeof(*user_data)); + if (user_data == NULL) { + weston_log("%s: memory allocation fails\n", __func__); + return; + } + + user_data->alpha = wl_fixed_to_double(start_alpha); + + create_visibility_transition(surface, + wl_fixed_to_double(start_alpha), + 0.0, // dest_alpha + user_data, + visibility_off_transition_destroy, + duration); +} + +/* move layer transition */ + +struct move_layer_data { + struct ivi_layout_layer *layer; + int32_t start_x; + int32_t start_y; + int32_t end_x; + int32_t end_y; + ivi_layout_transition_destroy_user_func destroy_func; +}; + +static void +transition_move_layer_user_frame(struct ivi_layout_transition *transition) +{ + struct move_layer_data *data = transition->private_data; + struct ivi_layout_layer *layer = data->layer; + + const float current = time_to_nowpos(transition); + + const int32_t dest_x = data->start_x + + (data->end_x - data->start_x) * current; + + const int32_t dest_y = data->start_y + + (data->end_y - data->start_y) * current; + + ivi_layout_layer_set_position(layer, dest_x, dest_y); +} + +static void +transition_move_layer_destroy(struct ivi_layout_transition *transition) +{ + struct move_layer_data *data = transition->private_data; + + if (data->destroy_func) + data->destroy_func(transition->user_data); + + free(data); + transition->private_data = NULL; +} + +static int32_t +is_transition_move_layer_func(struct move_layer_data *data, + struct ivi_layout_layer *layer) +{ + return data->layer == layer; +} + + +static struct ivi_layout_transition * +create_move_layer_transition( + struct ivi_layout_layer *layer, + int32_t start_x, int32_t start_y, + int32_t end_x, int32_t end_y, + void *user_data, + ivi_layout_transition_destroy_user_func destroy_user_func, + uint32_t duration) +{ + struct ivi_layout_transition *transition; + struct move_layer_data *data; + + transition = create_layout_transition(); + if (transition == NULL) + return NULL; + + data = malloc(sizeof(*data)); + if (data == NULL) { + weston_log("%s: memory allocation fails\n", __func__); + return NULL; + } + + transition->type = IVI_LAYOUT_TRANSITION_LAYER_MOVE; + transition->is_transition_func = (ivi_layout_is_transition_func)is_transition_move_layer_func; + + transition->frame_func = transition_move_layer_user_frame; + transition->destroy_func = transition_move_layer_destroy; + transition->private_data = data; + transition->user_data = user_data; + + if (duration != 0) + transition->time_duration = duration; + + data->layer = layer; + data->start_x = start_x; + data->start_y = start_y; + data->end_x = end_x; + data->end_y = end_y; + data->destroy_func = destroy_user_func; + + return transition; +} + +void +ivi_layout_transition_move_layer(struct ivi_layout_layer *layer, + int32_t dest_x, int32_t dest_y, + uint32_t duration) +{ + int32_t start_pos_x = 0; + int32_t start_pos_y = 0; + struct ivi_layout_transition *transition = NULL; + + ivi_layout_layer_get_position(layer, &start_pos_x, &start_pos_y); + + transition = create_move_layer_transition( + layer, + start_pos_x, start_pos_y, + dest_x, dest_y, + NULL, NULL, + duration); + + layout_transition_register(transition); + + return; +} + +void +ivi_layout_transition_move_layer_cancel(struct ivi_layout_layer *layer) +{ + struct ivi_layout_transition *transition = + get_transition_from_type_and_id( + IVI_LAYOUT_TRANSITION_LAYER_MOVE, + layer); + if (transition) { + layout_transition_destroy(transition); + } +} + +/* fade layer transition */ +struct fade_layer_data { + struct ivi_layout_layer *layer; + uint32_t is_fade_in; + double start_alpha; + double end_alpha; + ivi_layout_transition_destroy_user_func destroy_func; +}; + +static void +transition_fade_layer_destroy(struct ivi_layout_transition *transition) +{ + struct fade_layer_data *data = transition->private_data; + transition->private_data = NULL; + + free(data); +} + +static void +transition_fade_layer_user_frame(struct ivi_layout_transition *transition) +{ + double current = time_to_nowpos(transition); + struct fade_layer_data *data = transition->private_data; + double alpha = data->start_alpha + + (data->end_alpha - data->start_alpha) * current; + wl_fixed_t fixed_alpha = wl_fixed_from_double(alpha); + + int32_t is_done = transition->is_done; + bool is_visible = !is_done || data->is_fade_in; + + ivi_layout_layer_set_opacity(data->layer, fixed_alpha); + ivi_layout_layer_set_visibility(data->layer, is_visible); +} + +static int32_t +is_transition_fade_layer_func(struct fade_layer_data *data, + struct ivi_layout_layer *layer) +{ + return data->layer == layer; +} + +void +ivi_layout_transition_fade_layer( + struct ivi_layout_layer *layer, + uint32_t is_fade_in, + double start_alpha, double end_alpha, + void* user_data, + ivi_layout_transition_destroy_user_func destroy_func, + uint32_t duration) +{ + struct ivi_layout_transition *transition; + struct fade_layer_data *data = NULL; + wl_fixed_t fixed_opacity = 0.0; + double now_opacity = 0.0; + double remain = 0.0; + + transition = get_transition_from_type_and_id( + IVI_LAYOUT_TRANSITION_LAYER_FADE, + layer); + if (transition) { + /* transition update */ + data = transition->private_data; + + /* FIXME */ + fixed_opacity = ivi_layout_layer_get_opacity(layer); + now_opacity = wl_fixed_to_double(fixed_opacity); + remain = 0.0; + + data->is_fade_in = is_fade_in; + data->start_alpha = now_opacity; + data->end_alpha = end_alpha; + + remain = is_fade_in? 1.0 - now_opacity : now_opacity; + transition->time_start = 0; + transition->time_elapsed = 0; + transition->time_duration = duration * remain; + + return; + } + + transition = create_layout_transition(); + if (transition == NULL) + return; + + data = malloc(sizeof(*data)); + if (data == NULL) { + weston_log("%s: memory allocation fails\n", __func__); + return; + } + + transition->type = IVI_LAYOUT_TRANSITION_LAYER_FADE; + transition->is_transition_func = (ivi_layout_is_transition_func)is_transition_fade_layer_func; + + transition->private_data = data; + transition->user_data = user_data; + + transition->frame_func = transition_fade_layer_user_frame; + transition->destroy_func = transition_fade_layer_destroy; + + if (duration != 0) + transition->time_duration = duration; + + data->layer = layer; + data->is_fade_in = is_fade_in; + data->start_alpha = start_alpha; + data->end_alpha = end_alpha; + data->destroy_func = destroy_func; + + layout_transition_register(transition); + + return; +} + diff --git a/ivi-shell/ivi-layout.c b/ivi-shell/ivi-layout.c new file mode 100644 index 0000000..51d0a8d --- /dev/null +++ b/ivi-shell/ivi-layout.c @@ -0,0 +1,3011 @@ +/* + * Copyright (C) 2013 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. + */ + +/** + * Implementation of ivi-layout library. The actual view on ivi_screen is + * not updated till calling ivi_layout_commit_changes. A overview from + * calling API for updating properties of ivi_surface/ivi_layer to asking + * compositor to compose them by using weston_compositor_schedule_repaint, + * 0/ initialize this library by ivi_layout_init_with_compositor + * with (struct weston_compositor *ec) from ivi-shell. + * 1/ When a API for updating properties of ivi_surface/ivi_layer, it updates + * pending prop of ivi_surface/ivi_layer/ivi_screen which are structure to + * store properties. + * 2/ Before calling commitChanges, in case of calling a API to get a property, + * return current property, not pending property. + * 3/ At the timing of calling ivi_layout_commitChanges, pending properties + * are applied to properties. + * + * *) ivi_layout_commitChanges is also called by transition animation + * per each frame. See ivi-layout-transition.c in details. Transition + * animation interpolates frames between previous properties of ivi_surface + * and new ones. + * For example, when a property of ivi_surface is changed from invisibility + * to visibility, it behaves like fade-in. When ivi_layout_commitChange is + * called during transition animation, it cancels the transition and + * re-start transition to new properties from current properties of final + * frame just before the the cancellation. + * + * 4/ According properties, set transformation by using weston_matrix and + * weston_view per ivi_surfaces and ivi_layers in while loop. + * 5/ Set damage and trigger transform by using weston_view_geometry_dirty. + * 6/ Notify update of properties. + * 7/ Trigger composition by weston_compositor_schedule_repaint. + * + */ +#include "config.h" + +#include +#include + +#include "compositor.h" +#include "ivi-layout-export.h" +#include "ivi-layout-private.h" + +#include "shared/helpers.h" +#include "shared/os-compatibility.h" + +#define max(a, b) ((a) > (b) ? (a) : (b)) + +struct link_layer { + struct ivi_layout_layer *ivilayer; + struct wl_list link; + struct wl_list link_to_layer; +}; + +struct link_screen { + struct ivi_layout_screen *iviscrn; + struct wl_list link; + struct wl_list link_to_screen; +}; + +struct listener_layout_notification { + void *userdata; + struct wl_listener listener; +}; + +struct ivi_layout; + +struct ivi_layout_screen { + struct wl_list link; + struct wl_list link_to_layer; + uint32_t id_screen; + + struct ivi_layout *layout; + struct weston_output *output; + + struct { + struct wl_list layer_list; + struct wl_list link; + } pending; + + struct { + int dirty; + struct wl_list layer_list; + struct wl_list link; + } order; +}; + +struct ivi_layout_notification_callback { + void *callback; + void *data; +}; + +struct ivi_rectangle +{ + int32_t x; + int32_t y; + int32_t width; + int32_t height; +}; + +static void +remove_notification(struct wl_list *listener_list, void *callback, void *userdata); + +static struct ivi_layout ivilayout = {0}; + +struct ivi_layout * +get_instance(void) +{ + return &ivilayout; +} + +/** + * Internal API to add/remove a link to ivi_surface from ivi_layer. + */ +static void +add_link_to_surface(struct ivi_layout_layer *ivilayer, + struct link_layer *link_layer) +{ + struct link_layer *link = NULL; + + wl_list_for_each(link, &ivilayer->link_to_surface, link_to_layer) { + if (link == link_layer) + return; + } + + wl_list_insert(&ivilayer->link_to_surface, &link_layer->link_to_layer); +} + +static void +remove_link_to_surface(struct ivi_layout_layer *ivilayer) +{ + struct link_layer *link = NULL; + struct link_layer *next = NULL; + + wl_list_for_each_safe(link, next, &ivilayer->link_to_surface, link_to_layer) { + wl_list_remove(&link->link_to_layer); + wl_list_remove(&link->link); + free(link); + } + + wl_list_init(&ivilayer->link_to_surface); +} + +/** + * Internal API to add a link to ivi_layer from ivi_screen. + */ +static void +add_link_to_layer(struct ivi_layout_screen *iviscrn, + struct link_screen *link_screen) +{ + wl_list_insert(&iviscrn->link_to_layer, &link_screen->link_to_screen); +} + +/** + * Internal API to add/remove a ivi_surface from ivi_layer. + */ +static void +add_ordersurface_to_layer(struct ivi_layout_surface *ivisurf, + struct ivi_layout_layer *ivilayer) +{ + struct link_layer *link_layer = NULL; + + link_layer = malloc(sizeof *link_layer); + if (link_layer == NULL) { + weston_log("fails to allocate memory\n"); + return; + } + + link_layer->ivilayer = ivilayer; + wl_list_insert(&ivisurf->layer_list, &link_layer->link); + add_link_to_surface(ivilayer, link_layer); +} + +static void +remove_ordersurface_from_layer(struct ivi_layout_surface *ivisurf) +{ + struct link_layer *link_layer = NULL; + struct link_layer *next = NULL; + + wl_list_for_each_safe(link_layer, next, &ivisurf->layer_list, link) { + wl_list_remove(&link_layer->link); + wl_list_remove(&link_layer->link_to_layer); + free(link_layer); + } + wl_list_init(&ivisurf->layer_list); +} + +/** + * Internal API to add/remove a ivi_layer to/from ivi_screen. + */ +static void +add_orderlayer_to_screen(struct ivi_layout_layer *ivilayer, + struct ivi_layout_screen *iviscrn) +{ + struct link_screen *link_scrn = NULL; + + link_scrn = malloc(sizeof *link_scrn); + if (link_scrn == NULL) { + weston_log("fails to allocate memory\n"); + return; + } + + link_scrn->iviscrn = iviscrn; + wl_list_insert(&ivilayer->screen_list, &link_scrn->link); + add_link_to_layer(iviscrn, link_scrn); +} + +static void +remove_orderlayer_from_screen(struct ivi_layout_layer *ivilayer) +{ + struct link_screen *link_scrn = NULL; + struct link_screen *next = NULL; + + wl_list_for_each_safe(link_scrn, next, &ivilayer->screen_list, link) { + wl_list_remove(&link_scrn->link); + wl_list_remove(&link_scrn->link_to_screen); + free(link_scrn); + } + wl_list_init(&ivilayer->screen_list); +} + +/** + * Internal API to add/remove a ivi_layer to/from ivi_screen. + */ +static struct ivi_layout_surface * +get_surface(struct wl_list *surf_list, uint32_t id_surface) +{ + struct ivi_layout_surface *ivisurf; + + wl_list_for_each(ivisurf, surf_list, link) { + if (ivisurf->id_surface == id_surface) { + return ivisurf; + } + } + + return NULL; +} + +static struct ivi_layout_layer * +get_layer(struct wl_list *layer_list, uint32_t id_layer) +{ + struct ivi_layout_layer *ivilayer; + + wl_list_for_each(ivilayer, layer_list, link) { + if (ivilayer->id_layer == id_layer) { + return ivilayer; + } + } + + return NULL; +} + +static void +remove_configured_listener(struct ivi_layout_surface *ivisurf) +{ + struct wl_listener *link = NULL; + struct wl_listener *next = NULL; + + wl_list_for_each_safe(link, next, &ivisurf->configured.listener_list, link) { + wl_list_remove(&link->link); + } +} + +static void +remove_all_notification(struct wl_list *listener_list) +{ + struct wl_listener *listener = NULL; + struct wl_listener *next = NULL; + + wl_list_for_each_safe(listener, next, listener_list, link) { + struct listener_layout_notification *notification = NULL; + wl_list_remove(&listener->link); + + notification = + container_of(listener, + struct listener_layout_notification, + listener); + + free(notification->userdata); + free(notification); + } +} + +static void +ivi_layout_surface_remove_notification(struct ivi_layout_surface *ivisurf) +{ + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_remove_notification: invalid argument\n"); + return; + } + + remove_all_notification(&ivisurf->property_changed.listener_list); +} + +static void +ivi_layout_surface_remove_notification_by_callback(struct ivi_layout_surface *ivisurf, + surface_property_notification_func callback, + void *userdata) +{ + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_remove_notification_by_callback: invalid argument\n"); + return; + } + + remove_notification(&ivisurf->property_changed.listener_list, callback, userdata); +} + +/** + * Called at destruction of wl_surface/ivi_surface + */ +void +ivi_layout_surface_destroy(struct ivi_layout_surface *ivisurf) +{ + struct ivi_layout *layout = get_instance(); + + if (ivisurf == NULL) { + weston_log("%s: invalid argument\n", __func__); + return; + } + + wl_list_remove(&ivisurf->transform.link); + wl_list_remove(&ivisurf->pending.link); + wl_list_remove(&ivisurf->order.link); + wl_list_remove(&ivisurf->link); + remove_ordersurface_from_layer(ivisurf); + + wl_signal_emit(&layout->surface_notification.removed, ivisurf); + + remove_configured_listener(ivisurf); + + ivi_layout_surface_remove_notification(ivisurf); + + free(ivisurf); +} + +/** + * Internal API to check ivi_layer/ivi_surface already added in ivi_layer/ivi_screen. + * Called by ivi_layout_layer_add_surface/ivi_layout_screenAddLayer + */ +static int +is_surface_in_layer(struct ivi_layout_surface *ivisurf, + struct ivi_layout_layer *ivilayer) +{ + struct ivi_layout_surface *surf = NULL; + + wl_list_for_each(surf, &ivilayer->pending.surface_list, pending.link) { + if (surf->id_surface == ivisurf->id_surface) { + return 1; + } + } + + return 0; +} + +static int +is_layer_in_screen(struct ivi_layout_layer *ivilayer, + struct ivi_layout_screen *iviscrn) +{ + struct ivi_layout_layer *layer = NULL; + + wl_list_for_each(layer, &iviscrn->pending.layer_list, pending.link) { + if (layer->id_layer == ivilayer->id_layer) { + return 1; + } + } + + return 0; +} + +/** + * Internal API to initialize ivi_screens found from output_list of weston_compositor. + * Called by ivi_layout_init_with_compositor. + */ +static void +create_screen(struct weston_compositor *ec) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_screen *iviscrn = NULL; + struct weston_output *output = NULL; + int32_t count = 0; + + wl_list_for_each(output, &ec->output_list, link) { + iviscrn = calloc(1, sizeof *iviscrn); + if (iviscrn == NULL) { + weston_log("fails to allocate memory\n"); + continue; + } + + iviscrn->layout = layout; + + iviscrn->id_screen = count; + count++; + + iviscrn->output = output; + + wl_list_init(&iviscrn->pending.layer_list); + wl_list_init(&iviscrn->pending.link); + + wl_list_init(&iviscrn->order.layer_list); + wl_list_init(&iviscrn->order.link); + + wl_list_init(&iviscrn->link_to_layer); + + wl_list_insert(&layout->screen_list, &iviscrn->link); + } +} + +/** + * Internal APIs to initialize properties of ivi_surface/ivi_layer when they are created. + */ +static void +init_layer_properties(struct ivi_layout_layer_properties *prop, + int32_t width, int32_t height) +{ + memset(prop, 0, sizeof *prop); + prop->opacity = wl_fixed_from_double(1.0); + prop->source_width = width; + prop->source_height = height; + prop->dest_width = width; + prop->dest_height = height; +} + +static void +init_surface_properties(struct ivi_layout_surface_properties *prop) +{ + memset(prop, 0, sizeof *prop); + prop->opacity = wl_fixed_from_double(1.0); + /* + * FIXME: this shall be finxed by ivi-layout-transition. + */ + prop->dest_width = 1; + prop->dest_height = 1; +} + +/** + * Internal APIs to be called from ivi_layout_commit_changes. + */ +static void +update_opacity(struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface *ivisurf) +{ + double layer_alpha = wl_fixed_to_double(ivilayer->prop.opacity); + double surf_alpha = wl_fixed_to_double(ivisurf->prop.opacity); + + if ((ivilayer->event_mask & IVI_NOTIFICATION_OPACITY) || + (ivisurf->event_mask & IVI_NOTIFICATION_OPACITY)) { + struct weston_view *tmpview = NULL; + wl_list_for_each(tmpview, &ivisurf->surface->views, surface_link) { + if (tmpview == NULL) { + continue; + } + tmpview->alpha = layer_alpha * surf_alpha; + } + } +} + +static void +get_rotate_values(enum wl_output_transform orientation, + float *v_sin, + float *v_cos) +{ + switch (orientation) { + case WL_OUTPUT_TRANSFORM_90: + *v_sin = 1.0f; + *v_cos = 0.0f; + break; + case WL_OUTPUT_TRANSFORM_180: + *v_sin = 0.0f; + *v_cos = -1.0f; + break; + case WL_OUTPUT_TRANSFORM_270: + *v_sin = -1.0f; + *v_cos = 0.0f; + break; + case WL_OUTPUT_TRANSFORM_NORMAL: + default: + *v_sin = 0.0f; + *v_cos = 1.0f; + break; + } +} + +static void +get_scale(enum wl_output_transform orientation, + float dest_width, + float dest_height, + float source_width, + float source_height, + float *scale_x, + float *scale_y) +{ + switch (orientation) { + case WL_OUTPUT_TRANSFORM_90: + *scale_x = dest_width / source_height; + *scale_y = dest_height / source_width; + break; + case WL_OUTPUT_TRANSFORM_180: + *scale_x = dest_width / source_width; + *scale_y = dest_height / source_height; + break; + case WL_OUTPUT_TRANSFORM_270: + *scale_x = dest_width / source_height; + *scale_y = dest_height / source_width; + break; + case WL_OUTPUT_TRANSFORM_NORMAL: + default: + *scale_x = dest_width / source_width; + *scale_y = dest_height / source_height; + break; + } +} + +static void +calc_transformation_matrix(struct ivi_rectangle *source_rect, + struct ivi_rectangle *dest_rect, + enum wl_output_transform orientation, + struct weston_matrix *m) +{ + float source_center_x; + float source_center_y; + float vsin; + float vcos; + float scale_x; + float scale_y; + float translate_x; + float translate_y; + + source_center_x = source_rect->x + source_rect->width * 0.5f; + source_center_y = source_rect->y + source_rect->height * 0.5f; + weston_matrix_translate(m, -source_center_x, -source_center_y, 0.0f); + + get_rotate_values(orientation, &vsin, &vcos); + weston_matrix_rotate_xy(m, vcos, vsin); + + get_scale(orientation, + dest_rect->width, + dest_rect->height, + source_rect->width, + source_rect->height, + &scale_x, + &scale_y); + weston_matrix_scale(m, scale_x, scale_y, 1.0f); + + translate_x = dest_rect->width * 0.5f + dest_rect->x; + translate_y = dest_rect->height * 0.5f + dest_rect->y; + weston_matrix_translate(m, translate_x, translate_y, 0.0f); +} + +/* + * This computes intersected rect_output from two ivi_rectangles + */ +static void +ivi_rectangle_intersect(const struct ivi_rectangle *rect1, + const struct ivi_rectangle *rect2, + struct ivi_rectangle *rect_output) +{ + int32_t rect1_right = rect1->x + rect1->width; + int32_t rect1_bottom = rect1->y + rect1->height; + int32_t rect2_right = rect2->x + rect2->width; + int32_t rect2_bottom = rect2->y + rect2->height; + + rect_output->x = max(rect1->x, rect2->x); + rect_output->y = max(rect1->y, rect2->y); + rect_output->width = rect1_right < rect2_right ? + rect1_right - rect_output->x : + rect2_right - rect_output->x; + rect_output->height = rect1_bottom < rect2_bottom ? + rect1_bottom - rect_output->y : + rect2_bottom - rect_output->y; + + if (rect_output->width < 0 || rect_output->height < 0) { + rect_output->width = 0; + rect_output->height = 0; + } +} + +/* + * Transform rect_input by the inverse of matrix, intersect with boundingbox, + * and store the result in rect_output. + * The boundingbox must be given in the same coordinate space as rect_output. + * Additionally, there are the following restrictions on the matrix: + * - no projective transformations + * - no skew + * - only multiples of 90-degree rotations supported + * + * In failure case of weston_matrix_invert, rect_output is set to boundingbox + * as a fail-safe with log. + */ +static void +calc_inverse_matrix_transform(const struct weston_matrix *matrix, + const struct ivi_rectangle *rect_input, + const struct ivi_rectangle *boundingbox, + struct ivi_rectangle *rect_output) +{ + struct weston_matrix m; + struct weston_vector top_left; + struct weston_vector bottom_right; + + assert(boundingbox != rect_output); + + if (weston_matrix_invert(&m, matrix) < 0) { + weston_log("ivi-shell: calc_inverse_matrix_transform fails to invert a matrix.\n"); + weston_log("ivi-shell: boundingbox is set to the rect_output.\n"); + rect_output->x = boundingbox->x; + rect_output->y = boundingbox->y; + rect_output->width = boundingbox->width; + rect_output->height = boundingbox->height; + } + + /* The vectors and matrices involved will always produce f[3] == 1.0. */ + top_left.f[0] = rect_input->x; + top_left.f[1] = rect_input->y; + top_left.f[2] = 0.0f; + top_left.f[3] = 1.0f; + + bottom_right.f[0] = rect_input->x + rect_input->width; + bottom_right.f[1] = rect_input->y + rect_input->height; + bottom_right.f[2] = 0.0f; + bottom_right.f[3] = 1.0f; + + weston_matrix_transform(&m, &top_left); + weston_matrix_transform(&m, &bottom_right); + + if (top_left.f[0] < bottom_right.f[0]) { + rect_output->x = top_left.f[0]; + rect_output->width = bottom_right.f[0] - rect_output->x; + } else { + rect_output->x = bottom_right.f[0]; + rect_output->width = top_left.f[0] - rect_output->x; + } + + if (top_left.f[1] < bottom_right.f[1]) { + rect_output->y = top_left.f[1]; + rect_output->height = bottom_right.f[1] - rect_output->y; + } else { + rect_output->y = bottom_right.f[1]; + rect_output->height = top_left.f[1] - rect_output->y; + } + + ivi_rectangle_intersect(rect_output, boundingbox, rect_output); +} + +/** + * This computes the whole transformation matrix:m from surface-local + * coordinates to global coordinates. It is assumed that + * weston_view::geometry.{x,y} are zero. + * + * Additionally, this computes the mask on surface-local coordinates as a + * ivi_rectangle. This can be set to weston_view_set_mask. + * + * The mask is computed by following steps + * - destination rectangle of layer is inversed to surface-local cooodinates + * by inversed matrix:m. + * - the area is intersected by intersected area between weston_surface and + * source rectangle of ivi_surface. + */ +static void +calc_surface_to_global_matrix_and_mask_to_weston_surface( + struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface *ivisurf, + struct weston_matrix *m, + struct ivi_rectangle *result) +{ + const struct ivi_layout_surface_properties *sp = &ivisurf->prop; + const struct ivi_layout_layer_properties *lp = &ivilayer->prop; + struct ivi_rectangle weston_surface_rect = { 0, + 0, + ivisurf->surface->width, + ivisurf->surface->height }; + struct ivi_rectangle surface_source_rect = { sp->source_x, + sp->source_y, + sp->source_width, + sp->source_height }; + struct ivi_rectangle surface_dest_rect = { sp->dest_x, + sp->dest_y, + sp->dest_width, + sp->dest_height }; + struct ivi_rectangle layer_source_rect = { lp->source_x, + lp->source_y, + lp->source_width, + lp->source_height }; + struct ivi_rectangle layer_dest_rect = { lp->dest_x, + lp->dest_y, + lp->dest_width, + lp->dest_height }; + struct ivi_rectangle surface_result; + + /* + * the whole transformation matrix:m from surface-local + * coordinates to global coordinates, which is computed by + * two steps, + * - surface-local coordinates to layer-local coordinates + * - layer-local coordinates to global coordinates + */ + calc_transformation_matrix(&surface_source_rect, + &surface_dest_rect, + sp->orientation, m); + + calc_transformation_matrix(&layer_source_rect, + &layer_dest_rect, + lp->orientation, m); + + /* this intersected ivi_rectangle would be used for masking + * weston_surface + */ + ivi_rectangle_intersect(&surface_source_rect, &weston_surface_rect, + &surface_result); + + /* calc masking area of weston_surface from m */ + calc_inverse_matrix_transform(m, + &layer_dest_rect, + &surface_result, + result); +} + +static void +update_prop(struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface *ivisurf) +{ + struct weston_view *tmpview; + struct ivi_rectangle r; + bool can_calc = true; + + if (!ivilayer->event_mask && !ivisurf->event_mask) { + return; + } + + update_opacity(ivilayer, ivisurf); + + wl_list_for_each(tmpview, &ivisurf->surface->views, surface_link) { + if (tmpview != NULL) { + break; + } + } + + if (ivisurf->prop.source_width == 0 || ivisurf->prop.source_height == 0) { + weston_log("ivi-shell: source rectangle is not yet set by ivi_layout_surface_set_source_rectangle\n"); + can_calc = false; + } + + if (ivisurf->prop.dest_width == 0 || ivisurf->prop.dest_height == 0) { + weston_log("ivi-shell: destination rectangle is not yet set by ivi_layout_surface_set_destination_rectangle\n"); + can_calc = false; + } + + if (can_calc) { + wl_list_remove(&ivisurf->transform.link); + weston_matrix_init(&ivisurf->transform.matrix); + + calc_surface_to_global_matrix_and_mask_to_weston_surface( + ivilayer, ivisurf, &ivisurf->transform.matrix, &r); + + if (tmpview != NULL) { + wl_list_insert(&tmpview->geometry.transformation_list, + &ivisurf->transform.link); + + weston_view_set_transform_parent(tmpview, NULL); + } + } + + ivisurf->update_count++; + + if (tmpview != NULL) { + weston_view_geometry_dirty(tmpview); + } + + if (ivisurf->surface != NULL) { + weston_surface_damage(ivisurf->surface); + } +} + +static void +commit_changes(struct ivi_layout *layout) +{ + struct ivi_layout_screen *iviscrn = NULL; + struct ivi_layout_layer *ivilayer = NULL; + struct ivi_layout_surface *ivisurf = NULL; + + wl_list_for_each(iviscrn, &layout->screen_list, link) { + wl_list_for_each(ivilayer, &iviscrn->order.layer_list, order.link) { + wl_list_for_each(ivisurf, &ivilayer->order.surface_list, order.link) { + update_prop(ivilayer, ivisurf); + } + } + } +} + +static void +commit_surface_list(struct ivi_layout *layout) +{ + struct ivi_layout_surface *ivisurf = NULL; + int32_t dest_x = 0; + int32_t dest_y = 0; + int32_t dest_width = 0; + int32_t dest_height = 0; + int32_t configured = 0; + + wl_list_for_each(ivisurf, &layout->surface_list, link) { + if (ivisurf->pending.prop.transition_type == IVI_LAYOUT_TRANSITION_VIEW_DEFAULT) { + dest_x = ivisurf->prop.dest_x; + dest_y = ivisurf->prop.dest_y; + dest_width = ivisurf->prop.dest_width; + dest_height = ivisurf->prop.dest_height; + + ivi_layout_transition_move_resize_view(ivisurf, + ivisurf->pending.prop.dest_x, + ivisurf->pending.prop.dest_y, + ivisurf->pending.prop.dest_width, + ivisurf->pending.prop.dest_height, + ivisurf->pending.prop.transition_duration); + + if (ivisurf->pending.prop.visibility) { + ivi_layout_transition_visibility_on(ivisurf, ivisurf->pending.prop.transition_duration); + } else { + ivi_layout_transition_visibility_off(ivisurf, ivisurf->pending.prop.transition_duration); + } + + ivisurf->prop = ivisurf->pending.prop; + ivisurf->prop.dest_x = dest_x; + ivisurf->prop.dest_y = dest_y; + ivisurf->prop.dest_width = dest_width; + ivisurf->prop.dest_height = dest_height; + ivisurf->prop.transition_type = IVI_LAYOUT_TRANSITION_NONE; + ivisurf->pending.prop.transition_type = IVI_LAYOUT_TRANSITION_NONE; + + } else if (ivisurf->pending.prop.transition_type == IVI_LAYOUT_TRANSITION_VIEW_DEST_RECT_ONLY) { + dest_x = ivisurf->prop.dest_x; + dest_y = ivisurf->prop.dest_y; + dest_width = ivisurf->prop.dest_width; + dest_height = ivisurf->prop.dest_height; + + ivi_layout_transition_move_resize_view(ivisurf, + ivisurf->pending.prop.dest_x, + ivisurf->pending.prop.dest_y, + ivisurf->pending.prop.dest_width, + ivisurf->pending.prop.dest_height, + ivisurf->pending.prop.transition_duration); + + ivisurf->prop = ivisurf->pending.prop; + ivisurf->prop.dest_x = dest_x; + ivisurf->prop.dest_y = dest_y; + ivisurf->prop.dest_width = dest_width; + ivisurf->prop.dest_height = dest_height; + + ivisurf->prop.transition_type = IVI_LAYOUT_TRANSITION_NONE; + ivisurf->pending.prop.transition_type = IVI_LAYOUT_TRANSITION_NONE; + + } else if (ivisurf->pending.prop.transition_type == IVI_LAYOUT_TRANSITION_VIEW_FADE_ONLY) { + configured = 0; + if (ivisurf->pending.prop.visibility) { + ivi_layout_transition_visibility_on(ivisurf, ivisurf->pending.prop.transition_duration); + } else { + ivi_layout_transition_visibility_off(ivisurf, ivisurf->pending.prop.transition_duration); + } + + if (ivisurf->prop.dest_width != ivisurf->pending.prop.dest_width || + ivisurf->prop.dest_height != ivisurf->pending.prop.dest_height) { + configured = 1; + } + + ivisurf->prop = ivisurf->pending.prop; + ivisurf->prop.transition_type = IVI_LAYOUT_TRANSITION_NONE; + ivisurf->pending.prop.transition_type = IVI_LAYOUT_TRANSITION_NONE; + + if (configured && !is_surface_transition(ivisurf)) + wl_signal_emit(&ivisurf->configured, ivisurf); + } else { + configured = 0; + if (ivisurf->prop.dest_width != ivisurf->pending.prop.dest_width || + ivisurf->prop.dest_height != ivisurf->pending.prop.dest_height) { + configured = 1; + } + + ivisurf->prop = ivisurf->pending.prop; + ivisurf->prop.transition_type = IVI_LAYOUT_TRANSITION_NONE; + ivisurf->pending.prop.transition_type = IVI_LAYOUT_TRANSITION_NONE; + + if (configured && !is_surface_transition(ivisurf)) + wl_signal_emit(&ivisurf->configured, ivisurf); + } + } +} + +static void +commit_layer_list(struct ivi_layout *layout) +{ + struct ivi_layout_layer *ivilayer = NULL; + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_surface *next = NULL; + + wl_list_for_each(ivilayer, &layout->layer_list, link) { + if (ivilayer->pending.prop.transition_type == IVI_LAYOUT_TRANSITION_LAYER_MOVE) { + ivi_layout_transition_move_layer(ivilayer, ivilayer->pending.prop.dest_x, ivilayer->pending.prop.dest_y, ivilayer->pending.prop.transition_duration); + } else if (ivilayer->pending.prop.transition_type == IVI_LAYOUT_TRANSITION_LAYER_FADE) { + ivi_layout_transition_fade_layer(ivilayer,ivilayer->pending.prop.is_fade_in, + ivilayer->pending.prop.start_alpha,ivilayer->pending.prop.end_alpha, + NULL, NULL, + ivilayer->pending.prop.transition_duration); + } + ivilayer->pending.prop.transition_type = IVI_LAYOUT_TRANSITION_NONE; + + ivilayer->prop = ivilayer->pending.prop; + + if (!ivilayer->order.dirty) { + continue; + } + + wl_list_for_each_safe(ivisurf, next, &ivilayer->order.surface_list, + order.link) { + remove_ordersurface_from_layer(ivisurf); + wl_list_remove(&ivisurf->order.link); + wl_list_init(&ivisurf->order.link); + ivisurf->event_mask |= IVI_NOTIFICATION_REMOVE; + } + + assert(wl_list_empty(&ivilayer->order.surface_list)); + + wl_list_for_each(ivisurf, &ivilayer->pending.surface_list, + pending.link) { + wl_list_remove(&ivisurf->order.link); + wl_list_insert(&ivilayer->order.surface_list, + &ivisurf->order.link); + add_ordersurface_to_layer(ivisurf, ivilayer); + ivisurf->event_mask |= IVI_NOTIFICATION_ADD; + } + + ivilayer->order.dirty = 0; + } +} + +static void +commit_screen_list(struct ivi_layout *layout) +{ + struct ivi_layout_screen *iviscrn = NULL; + struct ivi_layout_layer *ivilayer = NULL; + struct ivi_layout_layer *next = NULL; + struct ivi_layout_surface *ivisurf = NULL; + + wl_list_for_each(iviscrn, &layout->screen_list, link) { + if (iviscrn->order.dirty) { + wl_list_for_each_safe(ivilayer, next, + &iviscrn->order.layer_list, order.link) { + remove_orderlayer_from_screen(ivilayer); + wl_list_remove(&ivilayer->order.link); + wl_list_init(&ivilayer->order.link); + ivilayer->event_mask |= IVI_NOTIFICATION_REMOVE; + } + + assert(wl_list_empty(&iviscrn->order.layer_list)); + + wl_list_for_each(ivilayer, &iviscrn->pending.layer_list, + pending.link) { + wl_list_insert(&iviscrn->order.layer_list, + &ivilayer->order.link); + add_orderlayer_to_screen(ivilayer, iviscrn); + ivilayer->event_mask |= IVI_NOTIFICATION_ADD; + } + + iviscrn->order.dirty = 0; + } + + /* Clear view list of layout ivi_layer */ + wl_list_init(&layout->layout_layer.view_list); + + wl_list_for_each(ivilayer, &iviscrn->order.layer_list, order.link) { + if (ivilayer->prop.visibility == false) + continue; + + wl_list_for_each(ivisurf, &ivilayer->order.surface_list, order.link) { + struct weston_view *tmpview = NULL; + wl_list_for_each(tmpview, &ivisurf->surface->views, surface_link) { + if (tmpview != NULL) { + break; + } + } + + if (ivisurf->prop.visibility == false) + continue; + if (ivisurf->surface == NULL || tmpview == NULL) + continue; + + wl_list_insert(&layout->layout_layer.view_list, + &tmpview->layer_link); + + ivisurf->surface->output = iviscrn->output; + } + } + + break; + } +} + +static void +commit_transition(struct ivi_layout* layout) +{ + if (wl_list_empty(&layout->pending_transition_list)) { + return; + } + + wl_list_insert_list(&layout->transitions->transition_list, + &layout->pending_transition_list); + + wl_list_init(&layout->pending_transition_list); + + wl_event_source_timer_update(layout->transitions->event_source, 1); +} + +static void +send_surface_prop(struct ivi_layout_surface *ivisurf) +{ + wl_signal_emit(&ivisurf->property_changed, ivisurf); + ivisurf->event_mask = 0; +} + +static void +send_layer_prop(struct ivi_layout_layer *ivilayer) +{ + wl_signal_emit(&ivilayer->property_changed, ivilayer); + ivilayer->event_mask = 0; +} + +static void +send_prop(struct ivi_layout *layout) +{ + struct ivi_layout_layer *ivilayer = NULL; + struct ivi_layout_surface *ivisurf = NULL; + + wl_list_for_each_reverse(ivilayer, &layout->layer_list, link) { + if (ivilayer->event_mask) + send_layer_prop(ivilayer); + } + + wl_list_for_each_reverse(ivisurf, &layout->surface_list, link) { + if (ivisurf->event_mask) + send_surface_prop(ivisurf); + } +} + +static void +clear_surface_pending_list(struct ivi_layout_layer *ivilayer) +{ + struct ivi_layout_surface *surface_link = NULL; + struct ivi_layout_surface *surface_next = NULL; + + wl_list_for_each_safe(surface_link, surface_next, + &ivilayer->pending.surface_list, pending.link) { + wl_list_remove(&surface_link->pending.link); + wl_list_init(&surface_link->pending.link); + } +} + +static void +clear_surface_order_list(struct ivi_layout_layer *ivilayer) +{ + struct ivi_layout_surface *surface_link = NULL; + struct ivi_layout_surface *surface_next = NULL; + + wl_list_for_each_safe(surface_link, surface_next, + &ivilayer->order.surface_list, order.link) { + wl_list_remove(&surface_link->order.link); + wl_list_init(&surface_link->order.link); + } +} + +static void +layer_created(struct wl_listener *listener, void *data) +{ + struct ivi_layout_layer *ivilayer = data; + + struct listener_layout_notification *notification = + container_of(listener, + struct listener_layout_notification, + listener); + + struct ivi_layout_notification_callback *created_callback = + notification->userdata; + + ((layer_create_notification_func)created_callback->callback) + (ivilayer, created_callback->data); +} + +static void +layer_removed(struct wl_listener *listener, void *data) +{ + struct ivi_layout_layer *ivilayer = data; + + struct listener_layout_notification *notification = + container_of(listener, + struct listener_layout_notification, + listener); + + struct ivi_layout_notification_callback *removed_callback = + notification->userdata; + + ((layer_remove_notification_func)removed_callback->callback) + (ivilayer, removed_callback->data); +} + +static void +layer_prop_changed(struct wl_listener *listener, void *data) +{ + struct ivi_layout_layer *ivilayer = data; + + struct listener_layout_notification *layout_listener = + container_of(listener, + struct listener_layout_notification, + listener); + + struct ivi_layout_notification_callback *prop_callback = + layout_listener->userdata; + + ((layer_property_notification_func)prop_callback->callback) + (ivilayer, &ivilayer->prop, ivilayer->event_mask, prop_callback->data); +} + +static void +surface_created(struct wl_listener *listener, void *data) +{ + struct ivi_layout_surface *ivisurface = data; + + struct listener_layout_notification *notification = + container_of(listener, + struct listener_layout_notification, + listener); + + struct ivi_layout_notification_callback *created_callback = + notification->userdata; + + ((surface_create_notification_func)created_callback->callback) + (ivisurface, created_callback->data); +} + +static void +surface_removed(struct wl_listener *listener, void *data) +{ + struct ivi_layout_surface *ivisurface = data; + + struct listener_layout_notification *notification = + container_of(listener, + struct listener_layout_notification, + listener); + + struct ivi_layout_notification_callback *removed_callback = + notification->userdata; + + ((surface_remove_notification_func)removed_callback->callback) + (ivisurface, removed_callback->data); +} + +static void +surface_prop_changed(struct wl_listener *listener, void *data) +{ + struct ivi_layout_surface *ivisurf = data; + + struct listener_layout_notification *layout_listener = + container_of(listener, + struct listener_layout_notification, + listener); + + struct ivi_layout_notification_callback *prop_callback = + layout_listener->userdata; + + ((surface_property_notification_func)prop_callback->callback) + (ivisurf, &ivisurf->prop, ivisurf->event_mask, prop_callback->data); + + ivisurf->event_mask = 0; +} + +static void +surface_configure_changed(struct wl_listener *listener, + void *data) +{ + struct ivi_layout_surface *ivisurface = data; + + struct listener_layout_notification *notification = + container_of(listener, + struct listener_layout_notification, + listener); + + struct ivi_layout_notification_callback *configure_changed_callback = + notification->userdata; + + ((surface_configure_notification_func)configure_changed_callback->callback) + (ivisurface, configure_changed_callback->data); +} + +static int32_t +add_notification(struct wl_signal *signal, + wl_notify_func_t callback, + void *userdata) +{ + struct listener_layout_notification *notification = NULL; + + notification = malloc(sizeof *notification); + if (notification == NULL) { + weston_log("fails to allocate memory\n"); + free(userdata); + return IVI_FAILED; + } + + notification->listener.notify = callback; + notification->userdata = userdata; + + wl_signal_add(signal, ¬ification->listener); + + return IVI_SUCCEEDED; +} + +static void +remove_notification(struct wl_list *listener_list, void *callback, void *userdata) +{ + struct wl_listener *listener = NULL; + struct wl_listener *next = NULL; + + wl_list_for_each_safe(listener, next, listener_list, link) { + struct listener_layout_notification *notification = + container_of(listener, + struct listener_layout_notification, + listener); + + struct ivi_layout_notification_callback *notification_callback = + notification->userdata; + + if ((notification_callback->callback != callback) || + (notification_callback->data != userdata)) { + continue; + } + + wl_list_remove(&listener->link); + + free(notification->userdata); + free(notification); + } +} + +/** + * Exported APIs of ivi-layout library are implemented from here. + * Brief of APIs is described in ivi-layout-export.h. + */ +static int32_t +ivi_layout_add_notification_create_layer(layer_create_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_notification_callback *created_callback = NULL; + + if (callback == NULL) { + weston_log("ivi_layout_add_notification_create_layer: invalid argument\n"); + return IVI_FAILED; + } + + created_callback = malloc(sizeof *created_callback); + if (created_callback == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + created_callback->callback = callback; + created_callback->data = userdata; + + return add_notification(&layout->layer_notification.created, + layer_created, + created_callback); +} + +static void +ivi_layout_remove_notification_create_layer(layer_create_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + remove_notification(&layout->layer_notification.created.listener_list, callback, userdata); +} + +static int32_t +ivi_layout_add_notification_remove_layer(layer_remove_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_notification_callback *removed_callback = NULL; + + if (callback == NULL) { + weston_log("ivi_layout_add_notification_remove_layer: invalid argument\n"); + return IVI_FAILED; + } + + removed_callback = malloc(sizeof *removed_callback); + if (removed_callback == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + removed_callback->callback = callback; + removed_callback->data = userdata; + return add_notification(&layout->layer_notification.removed, + layer_removed, + removed_callback); +} + +static void +ivi_layout_remove_notification_remove_layer(layer_remove_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + remove_notification(&layout->layer_notification.removed.listener_list, callback, userdata); +} + +static int32_t +ivi_layout_add_notification_create_surface(surface_create_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_notification_callback *created_callback = NULL; + + if (callback == NULL) { + weston_log("ivi_layout_add_notification_create_surface: invalid argument\n"); + return IVI_FAILED; + } + + created_callback = malloc(sizeof *created_callback); + if (created_callback == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + created_callback->callback = callback; + created_callback->data = userdata; + + return add_notification(&layout->surface_notification.created, + surface_created, + created_callback); +} + +static void +ivi_layout_remove_notification_create_surface(surface_create_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + remove_notification(&layout->surface_notification.created.listener_list, callback, userdata); +} + +static int32_t +ivi_layout_add_notification_remove_surface(surface_remove_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_notification_callback *removed_callback = NULL; + + if (callback == NULL) { + weston_log("ivi_layout_add_notification_remove_surface: invalid argument\n"); + return IVI_FAILED; + } + + removed_callback = malloc(sizeof *removed_callback); + if (removed_callback == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + removed_callback->callback = callback; + removed_callback->data = userdata; + + return add_notification(&layout->surface_notification.removed, + surface_removed, + removed_callback); +} + +static void +ivi_layout_remove_notification_remove_surface(surface_remove_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + remove_notification(&layout->surface_notification.removed.listener_list, callback, userdata); +} + +static int32_t +ivi_layout_add_notification_configure_surface(surface_configure_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_notification_callback *configure_changed_callback = NULL; + if (callback == NULL) { + weston_log("ivi_layout_add_notification_configure_surface: invalid argument\n"); + return IVI_FAILED; + } + + configure_changed_callback = malloc(sizeof *configure_changed_callback); + if (configure_changed_callback == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + configure_changed_callback->callback = callback; + configure_changed_callback->data = userdata; + + return add_notification(&layout->surface_notification.configure_changed, + surface_configure_changed, + configure_changed_callback); +} + +static void +ivi_layout_remove_notification_configure_surface(surface_configure_notification_func callback, + void *userdata) +{ + struct ivi_layout *layout = get_instance(); + remove_notification(&layout->surface_notification.configure_changed.listener_list, callback, userdata); +} + +uint32_t +ivi_layout_get_id_of_surface(struct ivi_layout_surface *ivisurf) +{ + return ivisurf->id_surface; +} + +static uint32_t +ivi_layout_get_id_of_layer(struct ivi_layout_layer *ivilayer) +{ + return ivilayer->id_layer; +} + +static uint32_t +ivi_layout_get_id_of_screen(struct ivi_layout_screen *iviscrn) +{ + return iviscrn->id_screen; +} + +static struct ivi_layout_layer * +ivi_layout_get_layer_from_id(uint32_t id_layer) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_layer *ivilayer = NULL; + + wl_list_for_each(ivilayer, &layout->layer_list, link) { + if (ivilayer->id_layer == id_layer) { + return ivilayer; + } + } + + return NULL; +} + +struct ivi_layout_surface * +ivi_layout_get_surface_from_id(uint32_t id_surface) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_surface *ivisurf = NULL; + + wl_list_for_each(ivisurf, &layout->surface_list, link) { + if (ivisurf->id_surface == id_surface) { + return ivisurf; + } + } + + return NULL; +} + +static struct ivi_layout_screen * +ivi_layout_get_screen_from_id(uint32_t id_screen) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_screen *iviscrn = NULL; + + wl_list_for_each(iviscrn, &layout->screen_list, link) { +/* FIXME : select iviscrn from screen_list by id_screen */ + return iviscrn; + break; + } + + return NULL; +} + +static int32_t +ivi_layout_get_screen_resolution(struct ivi_layout_screen *iviscrn, + int32_t *pWidth, int32_t *pHeight) +{ + struct weston_output *output = NULL; + + if (iviscrn == NULL || pWidth == NULL || pHeight == NULL) { + weston_log("ivi_layout_get_screen_resolution: invalid argument\n"); + return IVI_FAILED; + } + + output = iviscrn->output; + *pWidth = output->current_mode->width; + *pHeight = output->current_mode->height; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_surface_add_notification(struct ivi_layout_surface *ivisurf, + surface_property_notification_func callback, + void *userdata) +{ + struct listener_layout_notification* notification = NULL; + struct ivi_layout_notification_callback *prop_callback = NULL; + + if (ivisurf == NULL || callback == NULL) { + weston_log("ivi_layout_surface_add_notification: invalid argument\n"); + return IVI_FAILED; + } + + notification = malloc(sizeof *notification); + if (notification == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + prop_callback = malloc(sizeof *prop_callback); + if (prop_callback == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + prop_callback->callback = callback; + prop_callback->data = userdata; + + notification->listener.notify = surface_prop_changed; + notification->userdata = prop_callback; + + wl_signal_add(&ivisurf->property_changed, ¬ification->listener); + + return IVI_SUCCEEDED; +} + +static const struct ivi_layout_layer_properties * +ivi_layout_get_properties_of_layer(struct ivi_layout_layer *ivilayer) +{ + if (ivilayer == NULL) { + weston_log("ivi_layout_get_properties_of_layer: invalid argument\n"); + return NULL; + } + + return &ivilayer->prop; +} + +static int32_t +ivi_layout_get_screens(int32_t *pLength, struct ivi_layout_screen ***ppArray) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_screen *iviscrn = NULL; + int32_t length = 0; + int32_t n = 0; + + if (pLength == NULL || ppArray == NULL) { + weston_log("ivi_layout_get_screens: invalid argument\n"); + return IVI_FAILED; + } + + length = wl_list_length(&layout->screen_list); + + if (length != 0) { + /* the Array must be free by module which called this function */ + *ppArray = calloc(length, sizeof(struct ivi_layout_screen *)); + if (*ppArray == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + wl_list_for_each(iviscrn, &layout->screen_list, link) { + (*ppArray)[n++] = iviscrn; + } + } + + *pLength = length; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_get_screens_under_layer(struct ivi_layout_layer *ivilayer, + int32_t *pLength, + struct ivi_layout_screen ***ppArray) +{ + struct link_screen *link_scrn = NULL; + int32_t length = 0; + int32_t n = 0; + + if (ivilayer == NULL || pLength == NULL || ppArray == NULL) { + weston_log("ivi_layout_get_screens_under_layer: invalid argument\n"); + return IVI_FAILED; + } + + length = wl_list_length(&ivilayer->screen_list); + + if (length != 0) { + /* the Array must be free by module which called this function */ + *ppArray = calloc(length, sizeof(struct ivi_layout_screen *)); + if (*ppArray == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + wl_list_for_each(link_scrn, &ivilayer->screen_list, link) { + (*ppArray)[n++] = link_scrn->iviscrn; + } + } + + *pLength = length; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_get_layers(int32_t *pLength, struct ivi_layout_layer ***ppArray) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_layer *ivilayer = NULL; + int32_t length = 0; + int32_t n = 0; + + if (pLength == NULL || ppArray == NULL) { + weston_log("ivi_layout_get_layers: invalid argument\n"); + return IVI_FAILED; + } + + length = wl_list_length(&layout->layer_list); + + if (length != 0) { + /* the Array must be free by module which called this function */ + *ppArray = calloc(length, sizeof(struct ivi_layout_layer *)); + if (*ppArray == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + wl_list_for_each(ivilayer, &layout->layer_list, link) { + (*ppArray)[n++] = ivilayer; + } + } + + *pLength = length; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_get_layers_on_screen(struct ivi_layout_screen *iviscrn, + int32_t *pLength, + struct ivi_layout_layer ***ppArray) +{ + struct ivi_layout_layer *ivilayer = NULL; + int32_t length = 0; + int32_t n = 0; + + if (iviscrn == NULL || pLength == NULL || ppArray == NULL) { + weston_log("ivi_layout_get_layers_on_screen: invalid argument\n"); + return IVI_FAILED; + } + + length = wl_list_length(&iviscrn->order.layer_list); + + if (length != 0) { + /* the Array must be free by module which called this function */ + *ppArray = calloc(length, sizeof(struct ivi_layout_layer *)); + if (*ppArray == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + wl_list_for_each(ivilayer, &iviscrn->order.layer_list, order.link) { + (*ppArray)[n++] = ivilayer; + } + } + + *pLength = length; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_get_layers_under_surface(struct ivi_layout_surface *ivisurf, + int32_t *pLength, + struct ivi_layout_layer ***ppArray) +{ + struct link_layer *link_layer = NULL; + int32_t length = 0; + int32_t n = 0; + + if (ivisurf == NULL || pLength == NULL || ppArray == NULL) { + weston_log("ivi_layout_getLayers: invalid argument\n"); + return IVI_FAILED; + } + + length = wl_list_length(&ivisurf->layer_list); + + if (length != 0) { + /* the Array must be free by module which called this function */ + *ppArray = calloc(length, sizeof(struct ivi_layout_layer *)); + if (*ppArray == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + wl_list_for_each(link_layer, &ivisurf->layer_list, link) { + (*ppArray)[n++] = link_layer->ivilayer; + } + } + + *pLength = length; + + return IVI_SUCCEEDED; +} + +static +int32_t +ivi_layout_get_surfaces(int32_t *pLength, struct ivi_layout_surface ***ppArray) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_surface *ivisurf = NULL; + int32_t length = 0; + int32_t n = 0; + + if (pLength == NULL || ppArray == NULL) { + weston_log("ivi_layout_get_surfaces: invalid argument\n"); + return IVI_FAILED; + } + + length = wl_list_length(&layout->surface_list); + + if (length != 0) { + /* the Array must be free by module which called this function */ + *ppArray = calloc(length, sizeof(struct ivi_layout_surface *)); + if (*ppArray == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + wl_list_for_each(ivisurf, &layout->surface_list, link) { + (*ppArray)[n++] = ivisurf; + } + } + + *pLength = length; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_get_surfaces_on_layer(struct ivi_layout_layer *ivilayer, + int32_t *pLength, + struct ivi_layout_surface ***ppArray) +{ + struct ivi_layout_surface *ivisurf = NULL; + int32_t length = 0; + int32_t n = 0; + + if (ivilayer == NULL || pLength == NULL || ppArray == NULL) { + weston_log("ivi_layout_getSurfaceIDsOnLayer: invalid argument\n"); + return IVI_FAILED; + } + + length = wl_list_length(&ivilayer->order.surface_list); + + if (length != 0) { + /* the Array must be free by module which called this function */ + *ppArray = calloc(length, sizeof(struct ivi_layout_surface *)); + if (*ppArray == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + wl_list_for_each(ivisurf, &ivilayer->order.surface_list, order.link) { + (*ppArray)[n++] = ivisurf; + } + } + + *pLength = length; + + return IVI_SUCCEEDED; +} + +static struct ivi_layout_layer * +ivi_layout_layer_create_with_dimension(uint32_t id_layer, + int32_t width, int32_t height) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_layer *ivilayer = NULL; + + ivilayer = get_layer(&layout->layer_list, id_layer); + if (ivilayer != NULL) { + weston_log("id_layer is already created\n"); + ++ivilayer->ref_count; + return ivilayer; + } + + ivilayer = calloc(1, sizeof *ivilayer); + if (ivilayer == NULL) { + weston_log("fails to allocate memory\n"); + return NULL; + } + + ivilayer->ref_count = 1; + wl_signal_init(&ivilayer->property_changed); + wl_list_init(&ivilayer->screen_list); + wl_list_init(&ivilayer->link_to_surface); + ivilayer->layout = layout; + ivilayer->id_layer = id_layer; + + init_layer_properties(&ivilayer->prop, width, height); + ivilayer->event_mask = 0; + + wl_list_init(&ivilayer->pending.surface_list); + wl_list_init(&ivilayer->pending.link); + ivilayer->pending.prop = ivilayer->prop; + + wl_list_init(&ivilayer->order.surface_list); + wl_list_init(&ivilayer->order.link); + + wl_list_insert(&layout->layer_list, &ivilayer->link); + + wl_signal_emit(&layout->layer_notification.created, ivilayer); + + return ivilayer; +} + +static void +ivi_layout_layer_remove_notification(struct ivi_layout_layer *ivilayer) +{ + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_remove_notification: invalid argument\n"); + return; + } + + remove_all_notification(&ivilayer->property_changed.listener_list); +} + +static void +ivi_layout_layer_remove_notification_by_callback(struct ivi_layout_layer *ivilayer, + layer_property_notification_func callback, + void *userdata) +{ + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_remove_notification_by_callback: invalid argument\n"); + return; + } + + remove_notification(&ivilayer->property_changed.listener_list, callback, userdata); +} + +static void +ivi_layout_layer_destroy(struct ivi_layout_layer *ivilayer) +{ + struct ivi_layout *layout = get_instance(); + + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_remove: invalid argument\n"); + return; + } + + if (--ivilayer->ref_count > 0) + return; + + wl_signal_emit(&layout->layer_notification.removed, ivilayer); + + clear_surface_pending_list(ivilayer); + clear_surface_order_list(ivilayer); + + wl_list_remove(&ivilayer->pending.link); + wl_list_remove(&ivilayer->order.link); + wl_list_remove(&ivilayer->link); + + remove_orderlayer_from_screen(ivilayer); + remove_link_to_surface(ivilayer); + ivi_layout_layer_remove_notification(ivilayer); + + free(ivilayer); +} + +int32_t +ivi_layout_layer_set_visibility(struct ivi_layout_layer *ivilayer, + bool newVisibility) +{ + struct ivi_layout_layer_properties *prop = NULL; + + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_set_visibility: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivilayer->pending.prop; + prop->visibility = newVisibility; + + if (ivilayer->prop.visibility != newVisibility) + ivilayer->event_mask |= IVI_NOTIFICATION_VISIBILITY; + else + ivilayer->event_mask &= ~IVI_NOTIFICATION_VISIBILITY; + + return IVI_SUCCEEDED; +} + +static bool +ivi_layout_layer_get_visibility(struct ivi_layout_layer *ivilayer) +{ + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_get_visibility: invalid argument\n"); + return false; + } + + return ivilayer->prop.visibility; +} + +int32_t +ivi_layout_layer_set_opacity(struct ivi_layout_layer *ivilayer, + wl_fixed_t opacity) +{ + struct ivi_layout_layer_properties *prop = NULL; + + if (ivilayer == NULL || + opacity < wl_fixed_from_double(0.0) || + wl_fixed_from_double(1.0) < opacity) { + weston_log("ivi_layout_layer_set_opacity: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivilayer->pending.prop; + prop->opacity = opacity; + + if (ivilayer->prop.opacity != opacity) + ivilayer->event_mask |= IVI_NOTIFICATION_OPACITY; + else + ivilayer->event_mask &= ~IVI_NOTIFICATION_OPACITY; + + return IVI_SUCCEEDED; +} + +wl_fixed_t +ivi_layout_layer_get_opacity(struct ivi_layout_layer *ivilayer) +{ + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_get_opacity: invalid argument\n"); + return wl_fixed_from_double(0.0); + } + + return ivilayer->prop.opacity; +} + +static int32_t +ivi_layout_layer_set_source_rectangle(struct ivi_layout_layer *ivilayer, + int32_t x, int32_t y, + int32_t width, int32_t height) +{ + struct ivi_layout_layer_properties *prop = NULL; + + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_set_source_rectangle: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivilayer->pending.prop; + prop->source_x = x; + prop->source_y = y; + prop->source_width = width; + prop->source_height = height; + + if (ivilayer->prop.source_x != x || ivilayer->prop.source_y != y || + ivilayer->prop.source_width != width || + ivilayer->prop.source_height != height) + ivilayer->event_mask |= IVI_NOTIFICATION_SOURCE_RECT; + else + ivilayer->event_mask &= ~IVI_NOTIFICATION_SOURCE_RECT; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_layer_set_destination_rectangle(struct ivi_layout_layer *ivilayer, + int32_t x, int32_t y, + int32_t width, int32_t height) +{ + struct ivi_layout_layer_properties *prop = NULL; + + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_set_destination_rectangle: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivilayer->pending.prop; + prop->dest_x = x; + prop->dest_y = y; + prop->dest_width = width; + prop->dest_height = height; + + if (ivilayer->prop.dest_x != x || ivilayer->prop.dest_y != y || + ivilayer->prop.dest_width != width || + ivilayer->prop.dest_height != height) + ivilayer->event_mask |= IVI_NOTIFICATION_DEST_RECT; + else + ivilayer->event_mask &= ~IVI_NOTIFICATION_DEST_RECT; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_layer_get_dimension(struct ivi_layout_layer *ivilayer, + int32_t *dest_width, int32_t *dest_height) +{ + if (ivilayer == NULL || dest_width == NULL || dest_height == NULL) { + weston_log("ivi_layout_layer_get_dimension: invalid argument\n"); + return IVI_FAILED; + } + + *dest_width = ivilayer->prop.dest_width; + *dest_height = ivilayer->prop.dest_height; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_layer_set_dimension(struct ivi_layout_layer *ivilayer, + int32_t dest_width, int32_t dest_height) +{ + struct ivi_layout_layer_properties *prop = NULL; + + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_set_dimension: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivilayer->pending.prop; + + prop->dest_width = dest_width; + prop->dest_height = dest_height; + + if (ivilayer->prop.dest_width != dest_width || + ivilayer->prop.dest_height != dest_height) + ivilayer->event_mask |= IVI_NOTIFICATION_DIMENSION; + else + ivilayer->event_mask &= ~IVI_NOTIFICATION_DIMENSION; + + return IVI_SUCCEEDED; +} + +int32_t +ivi_layout_layer_get_position(struct ivi_layout_layer *ivilayer, + int32_t *dest_x, int32_t *dest_y) +{ + if (ivilayer == NULL || dest_x == NULL || dest_y == NULL) { + weston_log("ivi_layout_layer_get_position: invalid argument\n"); + return IVI_FAILED; + } + + *dest_x = ivilayer->prop.dest_x; + *dest_y = ivilayer->prop.dest_y; + + return IVI_SUCCEEDED; +} + +int32_t +ivi_layout_layer_set_position(struct ivi_layout_layer *ivilayer, + int32_t dest_x, int32_t dest_y) +{ + struct ivi_layout_layer_properties *prop = NULL; + + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_set_position: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivilayer->pending.prop; + prop->dest_x = dest_x; + prop->dest_y = dest_y; + + if (ivilayer->prop.dest_x != dest_x || ivilayer->prop.dest_y != dest_y) + ivilayer->event_mask |= IVI_NOTIFICATION_POSITION; + else + ivilayer->event_mask &= ~IVI_NOTIFICATION_POSITION; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_layer_set_orientation(struct ivi_layout_layer *ivilayer, + enum wl_output_transform orientation) +{ + struct ivi_layout_layer_properties *prop = NULL; + + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_set_orientation: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivilayer->pending.prop; + prop->orientation = orientation; + + if (ivilayer->prop.orientation != orientation) + ivilayer->event_mask |= IVI_NOTIFICATION_ORIENTATION; + else + ivilayer->event_mask &= ~IVI_NOTIFICATION_ORIENTATION; + + return IVI_SUCCEEDED; +} + +static enum wl_output_transform +ivi_layout_layer_get_orientation(struct ivi_layout_layer *ivilayer) +{ + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_get_orientation: invalid argument\n"); + return 0; + } + + return ivilayer->prop.orientation; +} + +int32_t +ivi_layout_layer_set_render_order(struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface **pSurface, + int32_t number) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_surface *next = NULL; + uint32_t *id_surface = NULL; + int32_t i = 0; + + if (ivilayer == NULL) { + weston_log("ivi_layout_layer_set_render_order: invalid argument\n"); + return IVI_FAILED; + } + + clear_surface_pending_list(ivilayer); + + for (i = 0; i < number; i++) { + id_surface = &pSurface[i]->id_surface; + + wl_list_for_each_safe(ivisurf, next, &layout->surface_list, link) { + if (*id_surface != ivisurf->id_surface) { + continue; + } + + wl_list_remove(&ivisurf->pending.link); + wl_list_insert(&ivilayer->pending.surface_list, + &ivisurf->pending.link); + break; + } + } + + ivilayer->order.dirty = 1; + + return IVI_SUCCEEDED; +} + +int32_t +ivi_layout_surface_set_visibility(struct ivi_layout_surface *ivisurf, + bool newVisibility) +{ + struct ivi_layout_surface_properties *prop = NULL; + + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_set_visibility: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivisurf->pending.prop; + prop->visibility = newVisibility; + + if (ivisurf->prop.visibility != newVisibility) + ivisurf->event_mask |= IVI_NOTIFICATION_VISIBILITY; + else + ivisurf->event_mask &= ~IVI_NOTIFICATION_VISIBILITY; + + return IVI_SUCCEEDED; +} + +bool +ivi_layout_surface_get_visibility(struct ivi_layout_surface *ivisurf) +{ + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_get_visibility: invalid argument\n"); + return false; + } + + return ivisurf->prop.visibility; +} + +int32_t +ivi_layout_surface_set_opacity(struct ivi_layout_surface *ivisurf, + wl_fixed_t opacity) +{ + struct ivi_layout_surface_properties *prop = NULL; + + if (ivisurf == NULL || + opacity < wl_fixed_from_double(0.0) || + wl_fixed_from_double(1.0) < opacity) { + weston_log("ivi_layout_surface_set_opacity: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivisurf->pending.prop; + prop->opacity = opacity; + + if (ivisurf->prop.opacity != opacity) + ivisurf->event_mask |= IVI_NOTIFICATION_OPACITY; + else + ivisurf->event_mask &= ~IVI_NOTIFICATION_OPACITY; + + return IVI_SUCCEEDED; +} + +wl_fixed_t +ivi_layout_surface_get_opacity(struct ivi_layout_surface *ivisurf) +{ + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_get_opacity: invalid argument\n"); + return wl_fixed_from_double(0.0); + } + + return ivisurf->prop.opacity; +} + +int32_t +ivi_layout_surface_set_destination_rectangle(struct ivi_layout_surface *ivisurf, + int32_t x, int32_t y, + int32_t width, int32_t height) +{ + struct ivi_layout_surface_properties *prop = NULL; + + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_set_destination_rectangle: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivisurf->pending.prop; + prop->start_x = prop->dest_x; + prop->start_y = prop->dest_y; + prop->dest_x = x; + prop->dest_y = y; + prop->start_width = prop->dest_width; + prop->start_height = prop->dest_height; + prop->dest_width = width; + prop->dest_height = height; + + if (ivisurf->prop.dest_x != x || ivisurf->prop.dest_y != y || + ivisurf->prop.dest_width != width || + ivisurf->prop.dest_height != height) + ivisurf->event_mask |= IVI_NOTIFICATION_DEST_RECT; + else + ivisurf->event_mask &= ~IVI_NOTIFICATION_DEST_RECT; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_surface_set_dimension(struct ivi_layout_surface *ivisurf, + int32_t dest_width, int32_t dest_height) +{ + struct ivi_layout_surface_properties *prop = NULL; + + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_set_dimension: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivisurf->pending.prop; + prop->dest_width = dest_width; + prop->dest_height = dest_height; + + if (ivisurf->prop.dest_width != dest_width || + ivisurf->prop.dest_height != dest_height) + ivisurf->event_mask |= IVI_NOTIFICATION_DIMENSION; + else + ivisurf->event_mask &= ~IVI_NOTIFICATION_DIMENSION; + + return IVI_SUCCEEDED; +} + +int32_t +ivi_layout_surface_get_dimension(struct ivi_layout_surface *ivisurf, + int32_t *dest_width, int32_t *dest_height) +{ + if (ivisurf == NULL || dest_width == NULL || dest_height == NULL) { + weston_log("ivi_layout_surface_get_dimension: invalid argument\n"); + return IVI_FAILED; + } + + *dest_width = ivisurf->prop.dest_width; + *dest_height = ivisurf->prop.dest_height; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_surface_set_position(struct ivi_layout_surface *ivisurf, + int32_t dest_x, int32_t dest_y) +{ + struct ivi_layout_surface_properties *prop = NULL; + + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_set_position: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivisurf->pending.prop; + prop->dest_x = dest_x; + prop->dest_y = dest_y; + + if (ivisurf->prop.dest_x != dest_x || ivisurf->prop.dest_y != dest_y) + ivisurf->event_mask |= IVI_NOTIFICATION_POSITION; + else + ivisurf->event_mask &= ~IVI_NOTIFICATION_POSITION; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_surface_get_position(struct ivi_layout_surface *ivisurf, + int32_t *dest_x, int32_t *dest_y) +{ + if (ivisurf == NULL || dest_x == NULL || dest_y == NULL) { + weston_log("ivi_layout_surface_get_position: invalid argument\n"); + return IVI_FAILED; + } + + *dest_x = ivisurf->prop.dest_x; + *dest_y = ivisurf->prop.dest_y; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_surface_set_orientation(struct ivi_layout_surface *ivisurf, + enum wl_output_transform orientation) +{ + struct ivi_layout_surface_properties *prop = NULL; + + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_set_orientation: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivisurf->pending.prop; + prop->orientation = orientation; + + if (ivisurf->prop.orientation != orientation) + ivisurf->event_mask |= IVI_NOTIFICATION_ORIENTATION; + else + ivisurf->event_mask &= ~IVI_NOTIFICATION_ORIENTATION; + + return IVI_SUCCEEDED; +} + +static enum wl_output_transform +ivi_layout_surface_get_orientation(struct ivi_layout_surface *ivisurf) +{ + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_get_orientation: invalid argument\n"); + return 0; + } + + return ivisurf->prop.orientation; +} + +static int32_t +ivi_layout_screen_add_layer(struct ivi_layout_screen *iviscrn, + struct ivi_layout_layer *addlayer) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_layer *ivilayer = NULL; + struct ivi_layout_layer *next = NULL; + int is_layer_in_scrn = 0; + + if (iviscrn == NULL || addlayer == NULL) { + weston_log("ivi_layout_screen_add_layer: invalid argument\n"); + return IVI_FAILED; + } + + is_layer_in_scrn = is_layer_in_screen(addlayer, iviscrn); + if (is_layer_in_scrn == 1) { + weston_log("ivi_layout_screen_add_layer: addlayer is already available\n"); + return IVI_SUCCEEDED; + } + + wl_list_for_each_safe(ivilayer, next, &layout->layer_list, link) { + if (ivilayer->id_layer == addlayer->id_layer) { + wl_list_remove(&ivilayer->pending.link); + wl_list_insert(&iviscrn->pending.layer_list, + &ivilayer->pending.link); + break; + } + } + + iviscrn->order.dirty = 1; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_screen_set_render_order(struct ivi_layout_screen *iviscrn, + struct ivi_layout_layer **pLayer, + const int32_t number) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_layer *ivilayer = NULL; + struct ivi_layout_layer *next = NULL; + uint32_t *id_layer = NULL; + int32_t i = 0; + + if (iviscrn == NULL) { + weston_log("ivi_layout_screen_set_render_order: invalid argument\n"); + return IVI_FAILED; + } + + wl_list_for_each_safe(ivilayer, next, + &iviscrn->pending.layer_list, pending.link) { + wl_list_remove(&ivilayer->pending.link); + wl_list_init(&ivilayer->pending.link); + } + + assert(wl_list_empty(&iviscrn->pending.layer_list)); + + for (i = 0; i < number; i++) { + id_layer = &pLayer[i]->id_layer; + wl_list_for_each(ivilayer, &layout->layer_list, link) { + if (*id_layer != ivilayer->id_layer) { + continue; + } + + wl_list_remove(&ivilayer->pending.link); + wl_list_insert(&iviscrn->pending.layer_list, + &ivilayer->pending.link); + break; + } + } + + iviscrn->order.dirty = 1; + + return IVI_SUCCEEDED; +} + +static struct weston_output * +ivi_layout_screen_get_output(struct ivi_layout_screen *iviscrn) +{ + return iviscrn->output; +} + +/** + * This function is used by the additional ivi-module because of dumping ivi_surface sceenshot. + * The ivi-module, e.g. ivi-controller.so, is in wayland-ivi-extension of Genivi's Layer Management. + * This function is used to get the result of drawing by clients. + */ +static struct weston_surface * +ivi_layout_surface_get_weston_surface(struct ivi_layout_surface *ivisurf) +{ + return ivisurf != NULL ? ivisurf->surface : NULL; +} + +static int32_t +ivi_layout_surface_get_size(struct ivi_layout_surface *ivisurf, + int32_t *width, int32_t *height, + int32_t *stride) +{ + int32_t w; + int32_t h; + const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */ + + if (ivisurf == NULL || ivisurf->surface == NULL) { + weston_log("%s: invalid argument\n", __func__); + return IVI_FAILED; + } + + weston_surface_get_content_size(ivisurf->surface, &w, &h); + + if (width != NULL) + *width = w; + + if (height != NULL) + *height = h; + + if (stride != NULL) + *stride = w * bytespp; + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_layer_add_notification(struct ivi_layout_layer *ivilayer, + layer_property_notification_func callback, + void *userdata) +{ + struct ivi_layout_notification_callback *prop_callback = NULL; + + if (ivilayer == NULL || callback == NULL) { + weston_log("ivi_layout_layer_add_notification: invalid argument\n"); + return IVI_FAILED; + } + + prop_callback = malloc(sizeof *prop_callback); + if (prop_callback == NULL) { + weston_log("fails to allocate memory\n"); + return IVI_FAILED; + } + + prop_callback->callback = callback; + prop_callback->data = userdata; + + return add_notification(&ivilayer->property_changed, + layer_prop_changed, + prop_callback); +} + +static const struct ivi_layout_surface_properties * +ivi_layout_get_properties_of_surface(struct ivi_layout_surface *ivisurf) +{ + if (ivisurf == NULL) { + weston_log("ivi_layout_get_properties_of_surface: invalid argument\n"); + return NULL; + } + + return &ivisurf->prop; +} + +static int32_t +ivi_layout_layer_add_surface(struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface *addsurf) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_surface *next = NULL; + int is_surf_in_layer = 0; + + if (ivilayer == NULL || addsurf == NULL) { + weston_log("ivi_layout_layer_add_surface: invalid argument\n"); + return IVI_FAILED; + } + + is_surf_in_layer = is_surface_in_layer(addsurf, ivilayer); + if (is_surf_in_layer == 1) { + weston_log("ivi_layout_layer_add_surface: addsurf is already available\n"); + return IVI_SUCCEEDED; + } + + wl_list_for_each_safe(ivisurf, next, &layout->surface_list, link) { + if (ivisurf->id_surface == addsurf->id_surface) { + wl_list_remove(&ivisurf->pending.link); + wl_list_insert(&ivilayer->pending.surface_list, + &ivisurf->pending.link); + break; + } + } + + ivilayer->order.dirty = 1; + + return IVI_SUCCEEDED; +} + +static void +ivi_layout_layer_remove_surface(struct ivi_layout_layer *ivilayer, + struct ivi_layout_surface *remsurf) +{ + struct ivi_layout_surface *ivisurf = NULL; + struct ivi_layout_surface *next = NULL; + + if (ivilayer == NULL || remsurf == NULL) { + weston_log("ivi_layout_layer_remove_surface: invalid argument\n"); + return; + } + + wl_list_for_each_safe(ivisurf, next, + &ivilayer->pending.surface_list, pending.link) { + if (ivisurf->id_surface == remsurf->id_surface) { + wl_list_remove(&ivisurf->pending.link); + wl_list_init(&ivisurf->pending.link); + break; + } + } + + ivilayer->order.dirty = 1; +} + +static int32_t +ivi_layout_surface_set_source_rectangle(struct ivi_layout_surface *ivisurf, + int32_t x, int32_t y, + int32_t width, int32_t height) +{ + struct ivi_layout_surface_properties *prop = NULL; + + if (ivisurf == NULL) { + weston_log("ivi_layout_surface_set_source_rectangle: invalid argument\n"); + return IVI_FAILED; + } + + prop = &ivisurf->pending.prop; + prop->source_x = x; + prop->source_y = y; + prop->source_width = width; + prop->source_height = height; + + if (ivisurf->prop.source_x != x || ivisurf->prop.source_y != y || + ivisurf->prop.source_width != width || + ivisurf->prop.source_height != height) + ivisurf->event_mask |= IVI_NOTIFICATION_SOURCE_RECT; + else + ivisurf->event_mask &= ~IVI_NOTIFICATION_SOURCE_RECT; + + return IVI_SUCCEEDED; +} + +int32_t +ivi_layout_commit_changes(void) +{ + struct ivi_layout *layout = get_instance(); + + commit_surface_list(layout); + commit_layer_list(layout); + commit_screen_list(layout); + + commit_transition(layout); + + commit_changes(layout); + send_prop(layout); + weston_compositor_schedule_repaint(layout->compositor); + + return IVI_SUCCEEDED; +} + +static int32_t +ivi_layout_layer_set_transition(struct ivi_layout_layer *ivilayer, + enum ivi_layout_transition_type type, + uint32_t duration) +{ + if (ivilayer == NULL) { + weston_log("%s: invalid argument\n", __func__); + return -1; + } + + ivilayer->pending.prop.transition_type = type; + ivilayer->pending.prop.transition_duration = duration; + + return 0; +} + +static int32_t +ivi_layout_layer_set_fade_info(struct ivi_layout_layer* ivilayer, + uint32_t is_fade_in, + double start_alpha, double end_alpha) +{ + if (ivilayer == NULL) { + weston_log("%s: invalid argument\n", __func__); + return -1; + } + + ivilayer->pending.prop.is_fade_in = is_fade_in; + ivilayer->pending.prop.start_alpha = start_alpha; + ivilayer->pending.prop.end_alpha = end_alpha; + + return 0; +} + +static int32_t +ivi_layout_surface_set_transition_duration(struct ivi_layout_surface *ivisurf, + uint32_t duration) +{ + struct ivi_layout_surface_properties *prop; + + if (ivisurf == NULL) { + weston_log("%s: invalid argument\n", __func__); + return -1; + } + + prop = &ivisurf->pending.prop; + prop->transition_duration = duration*10; + return 0; +} + +static int32_t +ivi_layout_surface_set_transition(struct ivi_layout_surface *ivisurf, + enum ivi_layout_transition_type type, + uint32_t duration) +{ + struct ivi_layout_surface_properties *prop; + + if (ivisurf == NULL) { + weston_log("%s: invalid argument\n", __func__); + return -1; + } + + prop = &ivisurf->pending.prop; + prop->transition_type = type; + prop->transition_duration = duration; + return 0; +} + +static int32_t +ivi_layout_surface_dump(struct weston_surface *surface, + void *target, size_t size,int32_t x, int32_t y, + int32_t width, int32_t height) +{ + int result = 0; + + if (surface == NULL) { + weston_log("%s: invalid argument\n", __func__); + return IVI_FAILED; + } + + result = weston_surface_copy_content( + surface, target, size, + x, y, width, height); + + return result == 0 ? IVI_SUCCEEDED : IVI_FAILED; +} + +/** + * methods of interaction between ivi-shell with ivi-layout + */ +struct weston_view * +ivi_layout_get_weston_view(struct ivi_layout_surface *surface) +{ + struct weston_view *tmpview = NULL; + + if (surface == NULL) + return NULL; + + wl_list_for_each(tmpview, &surface->surface->views, surface_link) + { + if (tmpview != NULL) { + break; + } + } + return tmpview; +} + +void +ivi_layout_surface_configure(struct ivi_layout_surface *ivisurf, + int32_t width, int32_t height) +{ + struct ivi_layout *layout = get_instance(); + + /* emit callback which is set by ivi-layout api user */ + wl_signal_emit(&layout->surface_notification.configure_changed, + ivisurf); +} + +static int32_t +ivi_layout_surface_set_content_observer(struct ivi_layout_surface *ivisurf, + ivi_controller_surface_content_callback callback, + void* userdata) +{ + int32_t ret = IVI_FAILED; + + if (ivisurf != NULL) { + ivisurf->content_observer.callback = callback; + ivisurf->content_observer.userdata = userdata; + ret = IVI_SUCCEEDED; + } + return ret; +} + +struct ivi_layout_surface* +ivi_layout_surface_create(struct weston_surface *wl_surface, + uint32_t id_surface) +{ + struct ivi_layout *layout = get_instance(); + struct ivi_layout_surface *ivisurf = NULL; + struct weston_view *tmpview = NULL; + + if (wl_surface == NULL) { + weston_log("ivi_layout_surface_create: invalid argument\n"); + return NULL; + } + + ivisurf = get_surface(&layout->surface_list, id_surface); + if (ivisurf != NULL) { + if (ivisurf->surface != NULL) { + weston_log("id_surface(%d) is already created\n", id_surface); + return NULL; + } + } + + ivisurf = calloc(1, sizeof *ivisurf); + if (ivisurf == NULL) { + weston_log("fails to allocate memory\n"); + return NULL; + } + + wl_signal_init(&ivisurf->property_changed); + wl_signal_init(&ivisurf->configured); + wl_list_init(&ivisurf->layer_list); + ivisurf->id_surface = id_surface; + ivisurf->layout = layout; + + ivisurf->surface = wl_surface; + + tmpview = weston_view_create(wl_surface); + if (tmpview == NULL) { + weston_log("fails to allocate memory\n"); + } + + ivisurf->surface->width_from_buffer = 0; + ivisurf->surface->height_from_buffer = 0; + + weston_matrix_init(&ivisurf->transform.matrix); + wl_list_init(&ivisurf->transform.link); + + init_surface_properties(&ivisurf->prop); + ivisurf->event_mask = 0; + + ivisurf->pending.prop = ivisurf->prop; + wl_list_init(&ivisurf->pending.link); + + wl_list_init(&ivisurf->order.link); + wl_list_init(&ivisurf->order.layer_list); + + wl_list_insert(&layout->surface_list, &ivisurf->link); + + wl_signal_emit(&layout->surface_notification.created, ivisurf); + + return ivisurf; +} + +void +ivi_layout_init_with_compositor(struct weston_compositor *ec) +{ + struct ivi_layout *layout = get_instance(); + + layout->compositor = ec; + + wl_list_init(&layout->surface_list); + wl_list_init(&layout->layer_list); + wl_list_init(&layout->screen_list); + + wl_signal_init(&layout->layer_notification.created); + wl_signal_init(&layout->layer_notification.removed); + + wl_signal_init(&layout->surface_notification.created); + wl_signal_init(&layout->surface_notification.removed); + wl_signal_init(&layout->surface_notification.configure_changed); + + /* Add layout_layer at the last of weston_compositor.layer_list */ + weston_layer_init(&layout->layout_layer, ec->layer_list.prev); + + create_screen(ec); + + layout->transitions = ivi_layout_transition_set_create(ec); + wl_list_init(&layout->pending_transition_list); +} + + +void +ivi_layout_surface_add_configured_listener(struct ivi_layout_surface* ivisurf, + struct wl_listener* listener) +{ + wl_signal_add(&ivisurf->configured, listener); +} + +static struct ivi_controller_interface ivi_controller_interface = { + /** + * commit all changes + */ + .commit_changes = ivi_layout_commit_changes, + + /** + * surface controller interfaces + */ + .add_notification_create_surface = ivi_layout_add_notification_create_surface, + .remove_notification_create_surface = ivi_layout_remove_notification_create_surface, + .add_notification_remove_surface = ivi_layout_add_notification_remove_surface, + .remove_notification_remove_surface = ivi_layout_remove_notification_remove_surface, + .add_notification_configure_surface = ivi_layout_add_notification_configure_surface, + .remove_notification_configure_surface = ivi_layout_remove_notification_configure_surface, + .get_surfaces = ivi_layout_get_surfaces, + .get_id_of_surface = ivi_layout_get_id_of_surface, + .get_surface_from_id = ivi_layout_get_surface_from_id, + .get_properties_of_surface = ivi_layout_get_properties_of_surface, + .get_surfaces_on_layer = ivi_layout_get_surfaces_on_layer, + .surface_set_visibility = ivi_layout_surface_set_visibility, + .surface_get_visibility = ivi_layout_surface_get_visibility, + .surface_set_opacity = ivi_layout_surface_set_opacity, + .surface_get_opacity = ivi_layout_surface_get_opacity, + .surface_set_source_rectangle = ivi_layout_surface_set_source_rectangle, + .surface_set_destination_rectangle = ivi_layout_surface_set_destination_rectangle, + .surface_set_position = ivi_layout_surface_set_position, + .surface_get_position = ivi_layout_surface_get_position, + .surface_set_dimension = ivi_layout_surface_set_dimension, + .surface_get_dimension = ivi_layout_surface_get_dimension, + .surface_set_orientation = ivi_layout_surface_set_orientation, + .surface_get_orientation = ivi_layout_surface_get_orientation, + .surface_set_content_observer = ivi_layout_surface_set_content_observer, + .surface_add_notification = ivi_layout_surface_add_notification, + .surface_remove_notification = ivi_layout_surface_remove_notification, + .surface_get_weston_surface = ivi_layout_surface_get_weston_surface, + .surface_set_transition = ivi_layout_surface_set_transition, + .surface_set_transition_duration = ivi_layout_surface_set_transition_duration, + + /** + * layer controller interfaces + */ + .add_notification_create_layer = ivi_layout_add_notification_create_layer, + .remove_notification_create_layer = ivi_layout_remove_notification_create_layer, + .add_notification_remove_layer = ivi_layout_add_notification_remove_layer, + .remove_notification_remove_layer = ivi_layout_remove_notification_remove_layer, + .layer_create_with_dimension = ivi_layout_layer_create_with_dimension, + .layer_destroy = ivi_layout_layer_destroy, + .get_layers = ivi_layout_get_layers, + .get_id_of_layer = ivi_layout_get_id_of_layer, + .get_layer_from_id = ivi_layout_get_layer_from_id, + .get_properties_of_layer = ivi_layout_get_properties_of_layer, + .get_layers_under_surface = ivi_layout_get_layers_under_surface, + .get_layers_on_screen = ivi_layout_get_layers_on_screen, + .layer_set_visibility = ivi_layout_layer_set_visibility, + .layer_get_visibility = ivi_layout_layer_get_visibility, + .layer_set_opacity = ivi_layout_layer_set_opacity, + .layer_get_opacity = ivi_layout_layer_get_opacity, + .layer_set_source_rectangle = ivi_layout_layer_set_source_rectangle, + .layer_set_destination_rectangle = ivi_layout_layer_set_destination_rectangle, + .layer_set_position = ivi_layout_layer_set_position, + .layer_get_position = ivi_layout_layer_get_position, + .layer_set_dimension = ivi_layout_layer_set_dimension, + .layer_get_dimension = ivi_layout_layer_get_dimension, + .layer_set_orientation = ivi_layout_layer_set_orientation, + .layer_get_orientation = ivi_layout_layer_get_orientation, + .layer_add_surface = ivi_layout_layer_add_surface, + .layer_remove_surface = ivi_layout_layer_remove_surface, + .layer_set_render_order = ivi_layout_layer_set_render_order, + .layer_add_notification = ivi_layout_layer_add_notification, + .layer_remove_notification = ivi_layout_layer_remove_notification, + .layer_set_transition = ivi_layout_layer_set_transition, + + /** + * screen controller interfaces part1 + */ + .get_screen_from_id = ivi_layout_get_screen_from_id, + .get_screen_resolution = ivi_layout_get_screen_resolution, + .get_screens = ivi_layout_get_screens, + .get_screens_under_layer = ivi_layout_get_screens_under_layer, + .screen_add_layer = ivi_layout_screen_add_layer, + .screen_set_render_order = ivi_layout_screen_set_render_order, + .screen_get_output = ivi_layout_screen_get_output, + + /** + * animation + */ + .transition_move_layer_cancel = ivi_layout_transition_move_layer_cancel, + .layer_set_fade_info = ivi_layout_layer_set_fade_info, + + /** + * surface content dumping for debugging + */ + .surface_get_size = ivi_layout_surface_get_size, + .surface_dump = ivi_layout_surface_dump, + + /** + * remove notification by callback on property changes of ivi_surface/layer + */ + .surface_remove_notification_by_callback = ivi_layout_surface_remove_notification_by_callback, + .layer_remove_notification_by_callback = ivi_layout_layer_remove_notification_by_callback, + + /** + * screen controller interfaces part2 + */ + .get_id_of_screen = ivi_layout_get_id_of_screen +}; + +int +load_controller_modules(struct weston_compositor *compositor, const char *modules, + int *argc, char *argv[]) +{ + const char *p, *end; + char buffer[256]; + int (*controller_module_init)(struct weston_compositor *compositor, + int *argc, char *argv[], + const struct ivi_controller_interface *interface, + size_t interface_version); + + if (modules == NULL) + return 0; + + p = modules; + while (*p) { + end = strchrnul(p, ','); + snprintf(buffer, sizeof buffer, "%.*s", (int)(end - p), p); + + controller_module_init = weston_load_module(buffer, "controller_module_init"); + if (!controller_module_init) + return -1; + + if (controller_module_init(compositor, argc, argv, + &ivi_controller_interface, + sizeof(struct ivi_controller_interface)) != 0) { + weston_log("ivi-shell: Initialization of controller module fails"); + return -1; + } + + p = end; + while (*p == ',') + p++; + } + + return 0; +} diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c new file mode 100644 index 0000000..220a508 --- /dev/null +++ b/ivi-shell/ivi-shell.c @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2013 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. + */ + +/* + * ivi-shell supports a type of shell for In-Vehicle Infotainment system. + * In-Vehicle Infotainment system traditionally manages surfaces with global + * identification. A protocol, ivi_application, supports such a feature + * by implementing a request, ivi_application::surface_creation defined in + * ivi_application.xml. + * + * The ivi-shell explicitly loads a module to add business logic like how to + * layout surfaces by using internal ivi-layout APIs. + */ +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ivi-shell.h" +#include "ivi-application-server-protocol.h" +#include "ivi-layout-export.h" +#include "ivi-layout-private.h" +#include "shared/helpers.h" + +/* Representation of ivi_surface protocol object. */ +struct ivi_shell_surface +{ + struct wl_resource* resource; + struct ivi_shell *shell; + struct ivi_layout_surface *layout_surface; + + struct weston_surface *surface; + struct wl_listener surface_destroy_listener; + + uint32_t id_surface; + + int32_t width; + int32_t height; + + struct wl_list link; + + struct wl_listener configured_listener; +}; + +struct ivi_shell_setting +{ + char *ivi_module; + int developermode; +}; + +/* + * Implementation of ivi_surface + */ + +static void +surface_configure_notify(struct wl_listener *listener, void *data) +{ + struct ivi_layout_surface *layout_surf = + (struct ivi_layout_surface *)data; + + struct ivi_shell_surface *shell_surf = + container_of(listener, + struct ivi_shell_surface, + configured_listener); + + int32_t dest_width = 0; + int32_t dest_height = 0; + + ivi_layout_surface_get_dimension(layout_surf, + &dest_width, &dest_height); + + if (shell_surf->resource) + ivi_surface_send_configure(shell_surf->resource, + dest_width, dest_height); +} + +static void +ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t); + +static struct ivi_shell_surface * +get_ivi_shell_surface(struct weston_surface *surface) +{ + if (surface->configure == ivi_shell_surface_configure) + return surface->configure_private; + + return NULL; +} + +static void +ivi_shell_surface_configure(struct weston_surface *surface, + int32_t sx, int32_t sy) +{ + struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(surface); + + if (surface->width == 0 || surface->height == 0 || ivisurf == NULL) + return; + + if (ivisurf->width != surface->width || + ivisurf->height != surface->height) { + ivisurf->width = surface->width; + ivisurf->height = surface->height; + + ivi_layout_surface_configure(ivisurf->layout_surface, + surface->width, surface->height); + } +} + +static void +layout_surface_cleanup(struct ivi_shell_surface *ivisurf) +{ + assert(ivisurf->layout_surface != NULL); + + ivi_layout_surface_destroy(ivisurf->layout_surface); + ivisurf->layout_surface = NULL; + + ivisurf->surface->configure = NULL; + ivisurf->surface->configure_private = NULL; + ivisurf->surface = NULL; + + // destroy weston_surface destroy signal. + wl_list_remove(&ivisurf->surface_destroy_listener.link); +} + +/* + * The ivi_surface wl_resource destructor. + * + * Gets called via ivi_surface.destroy request or automatic wl_client clean-up. + */ +static void +shell_destroy_shell_surface(struct wl_resource *resource) +{ + struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource); + + if (ivisurf == NULL) + return; + + assert(ivisurf->resource == resource); + + if (ivisurf->layout_surface != NULL) + layout_surface_cleanup(ivisurf); + + wl_list_remove(&ivisurf->link); + + free(ivisurf); +} + +/* Gets called through the weston_surface destroy signal. */ +static void +shell_handle_surface_destroy(struct wl_listener *listener, void *data) +{ + struct ivi_shell_surface *ivisurf = + container_of(listener, struct ivi_shell_surface, + surface_destroy_listener); + + assert(ivisurf != NULL); + + if (ivisurf->layout_surface != NULL) + layout_surface_cleanup(ivisurf); +} + +/* Gets called, when a client sends ivi_surface.destroy request. */ +static void +surface_destroy(struct wl_client *client, struct wl_resource *resource) +{ + /* + * Fires the wl_resource destroy signal, and then calls + * ivi_surface wl_resource destructor: shell_destroy_shell_surface() + */ + wl_resource_destroy(resource); +} + +static const struct ivi_surface_interface surface_implementation = { + surface_destroy, +}; + +/** + * Request handler for ivi_application.surface_create. + * + * Creates an ivi_surface protocol object associated with the given wl_surface. + * ivi_surface protocol object is represented by struct ivi_shell_surface. + * + * \param client The client. + * \param resource The ivi_application protocol object. + * \param id_surface The IVI surface ID. + * \param surface_resource The wl_surface protocol object. + * \param id The protocol object id for the new ivi_surface protocol object. + * + * The wl_surface is given the ivi_surface role and associated with a unique + * IVI ID which is used to identify the surface in a controller + * (window manager). + */ +static void +application_surface_create(struct wl_client *client, + struct wl_resource *resource, + uint32_t id_surface, + struct wl_resource *surface_resource, + uint32_t id) +{ + struct ivi_shell *shell = wl_resource_get_user_data(resource); + struct ivi_shell_surface *ivisurf; + struct ivi_layout_surface *layout_surface; + struct weston_surface *weston_surface = + wl_resource_get_user_data(surface_resource); + struct wl_resource *res; + + /* check if a surface already has another role */ + if (weston_surface->configure) { + wl_resource_post_error(weston_surface->resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "surface->configure already " + "set"); + return; + } + + layout_surface = ivi_layout_surface_create(weston_surface, id_surface); + + /* check if id_ivi is already used for wl_surface*/ + if (layout_surface == NULL) { + wl_resource_post_error(resource, + IVI_APPLICATION_ERROR_IVI_ID, + "surface_id is already assigned " + "by another app"); + return; + } + + ivisurf = zalloc(sizeof *ivisurf); + if (ivisurf == NULL) { + wl_resource_post_no_memory(resource); + return; + } + + wl_list_init(&ivisurf->link); + wl_list_insert(&shell->ivi_surface_list, &ivisurf->link); + + ivisurf->shell = shell; + ivisurf->id_surface = id_surface; + + ivisurf->width = 0; + ivisurf->height = 0; + ivisurf->layout_surface = layout_surface; + ivisurf->configured_listener.notify = surface_configure_notify; + ivi_layout_surface_add_configured_listener(layout_surface, + &ivisurf->configured_listener); + /* + * The following code relies on wl_surface destruction triggering + * immediateweston_surface destruction + */ + ivisurf->surface_destroy_listener.notify = shell_handle_surface_destroy; + wl_signal_add(&weston_surface->destroy_signal, + &ivisurf->surface_destroy_listener); + + ivisurf->surface = weston_surface; + + weston_surface->configure = ivi_shell_surface_configure; + weston_surface->configure_private = ivisurf; + + res = wl_resource_create(client, &ivi_surface_interface, 1, id); + if (res == NULL) { + wl_client_post_no_memory(client); + return; + } + + ivisurf->resource = res; + + wl_resource_set_implementation(res, &surface_implementation, + ivisurf, shell_destroy_shell_surface); +} + +static const struct ivi_application_interface application_implementation = { + application_surface_create +}; + +/* + * Handle wl_registry.bind of ivi_application global singleton. + */ +static void +bind_ivi_application(struct wl_client *client, + void *data, uint32_t version, uint32_t id) +{ + struct ivi_shell *shell = data; + struct wl_resource *resource; + + resource = wl_resource_create(client, &ivi_application_interface, + 1, id); + + wl_resource_set_implementation(resource, + &application_implementation, + shell, NULL); +} + +struct weston_view * +get_default_view(struct weston_surface *surface) +{ + struct ivi_shell_surface *shsurf; + struct weston_view *view; + + if (!surface || wl_list_empty(&surface->views)) + return NULL; + + shsurf = get_ivi_shell_surface(surface); + if (shsurf && shsurf->layout_surface) { + view = ivi_layout_get_weston_view(shsurf->layout_surface); + if (view) + return view; + } + + wl_list_for_each(view, &surface->views, surface_link) { + if (weston_view_is_mapped(view)) + return view; + } + + return container_of(surface->views.next, + struct weston_view, surface_link); +} + +/* + * Called through the compositor's destroy signal. + */ +static void +shell_destroy(struct wl_listener *listener, void *data) +{ + struct ivi_shell *shell = + container_of(listener, struct ivi_shell, destroy_listener); + struct ivi_shell_surface *ivisurf, *next; + + input_panel_destroy(shell); + + wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) { + wl_list_remove(&ivisurf->link); + free(ivisurf); + } + + free(shell); +} + +static void +terminate_binding(struct weston_seat *seat, uint32_t time, + uint32_t key, void *data) +{ + struct weston_compositor *compositor = data; + + wl_display_terminate(compositor->wl_display); +} + +static void +init_ivi_shell(struct weston_compositor *compositor, struct ivi_shell *shell, + const struct ivi_shell_setting *setting) +{ + shell->compositor = compositor; + + wl_list_init(&shell->ivi_surface_list); + + weston_layer_init(&shell->input_panel_layer, NULL); + + if (setting->developermode) { +#if 0 + weston_install_debug_key_binding(compositor, MODIFIER_SUPER); +#endif + + weston_compositor_add_key_binding(compositor, KEY_BACKSPACE, + MODIFIER_CTRL | MODIFIER_ALT, + terminate_binding, + compositor); + } +} + +static int +ivi_shell_setting_create(struct ivi_shell_setting *dest, + struct weston_compositor *compositor, + int *argc, char *argv[]) +{ + int result = 0; + struct weston_config *config = compositor->config; + struct weston_config_section *section; + + const struct weston_option ivi_shell_options[] = { + { WESTON_OPTION_STRING, "ivi-module", 0, &dest->ivi_module }, + }; + + parse_options(ivi_shell_options, ARRAY_LENGTH(ivi_shell_options), + argc, argv); + + section = weston_config_get_section(config, "ivi-shell", NULL, NULL); + + if (!dest->ivi_module && + weston_config_section_get_string(section, "ivi-module", + &dest->ivi_module, NULL) < 0) { + weston_log("Error: ivi-shell: No ivi-module set\n"); + result = -1; + } + + weston_config_section_get_bool(section, "developermode", + &dest->developermode, 0); + + return result; +} + +/* + * Initialization of ivi-shell. + */ +WL_EXPORT int +module_init(struct weston_compositor *compositor, + int *argc, char *argv[]) +{ + struct ivi_shell *shell; + struct ivi_shell_setting setting = { }; + int retval = -1; + + shell = zalloc(sizeof *shell); + if (shell == NULL) + return -1; + + if (ivi_shell_setting_create(&setting, compositor, argc, argv) != 0) + return -1; + + init_ivi_shell(compositor, shell, &setting); + + shell->destroy_listener.notify = shell_destroy; + wl_signal_add(&compositor->destroy_signal, &shell->destroy_listener); + + if (input_panel_setup(shell) < 0) + goto out_settings; + + text_backend_init(compositor); + + if (wl_global_create(compositor->wl_display, + &ivi_application_interface, 1, + shell, bind_ivi_application) == NULL) + goto out_settings; + + ivi_layout_init_with_compositor(compositor); + + /* Call module_init of ivi-modules which are defined in weston.ini */ + if (load_controller_modules(compositor, setting.ivi_module, + argc, argv) < 0) + goto out_settings; + + retval = 0; + +out_settings: + free(setting.ivi_module); + + return retval; +} diff --git a/ivi-shell/ivi-shell.h b/ivi-shell/ivi-shell.h new file mode 100644 index 0000000..9a05eb2 --- /dev/null +++ b/ivi-shell/ivi-shell.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2013 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 "compositor.h" + +struct ivi_shell +{ + struct wl_listener destroy_listener; + + struct weston_compositor *compositor; + + struct wl_list ivi_surface_list; /* struct ivi_shell_surface::link */ + + struct text_backend *text_backend; + + struct wl_listener show_input_panel_listener; + struct wl_listener hide_input_panel_listener; + struct wl_listener update_input_panel_listener; + + struct weston_layer input_panel_layer; + + bool locked; + bool showing_input_panels; + + struct { + struct weston_surface *surface; + pixman_box32_t cursor_rectangle; + } text_input; + + struct { + struct wl_resource *binding; + struct wl_list surfaces; + } input_panel; +}; + +struct weston_view * +get_default_view(struct weston_surface *surface); + +int +input_panel_setup(struct ivi_shell *shell); + +void +input_panel_destroy(struct ivi_shell *shell); diff --git a/ivi-shell/weston.ini.in b/ivi-shell/weston.ini.in new file mode 100644 index 0000000..6c22633 --- /dev/null +++ b/ivi-shell/weston.ini.in @@ -0,0 +1,98 @@ +[core] +shell=@plugin_prefix@ivi-shell.so + +[ivi-shell] +ivi-module=@plugin_prefix@hmi-controller.so +ivi-shell-user-interface=@abs_top_builddir@/weston-ivi-shell-user-interface + +#developermode=true + +cursor-theme=default +cursor-size=32 + +base-layer-id=1000 +workspace-background-layer-id=2000 +workspace-layer-id=3000 +application-layer-id=4000 + +transition-duration=300 + +background-image=@abs_top_srcdir@/data/background.png +background-id=1001 +panel-image=@abs_top_srcdir@/data/panel.png +panel-id=1002 +tiling-image=@abs_top_srcdir@/data/tiling.png +tiling-id=1003 +sidebyside-image=@abs_top_srcdir@/data/sidebyside.png +sidebyside-id=1004 +fullscreen-image=@abs_top_srcdir@/data/fullscreen.png +fullscreen-id=1005 +random-image=@abs_top_srcdir@/data/random.png +random-id=1006 +home-image=@abs_top_srcdir@/data/home.png +home-id=1007 +workspace-background-color=0x99000000 +workspace-background-id=2001 + +[input-method] +path=@libexecdir@/weston-keyboard + +[ivi-launcher] +workspace-id=0 +icon-id=4001 +icon=@abs_top_srcdir@/data/icon_ivi_flower.png +path=@abs_top_builddir@/weston-flower + +[ivi-launcher] +workspace-id=0 +icon-id=4002 +icon=@abs_top_srcdir@/data/icon_ivi_clickdot.png +path=@abs_top_builddir@/weston-clickdot + +[ivi-launcher] +workspace-id=1 +icon-id=4003 +icon=@abs_top_srcdir@/data/icon_ivi_simple-egl.png +path=@abs_top_builddir@/weston-simple-egl + +[ivi-launcher] +workspace-id=1 +icon-id=4004 +icon=@abs_top_srcdir@/data/icon_ivi_simple-shm.png +path=@abs_top_builddir@/weston-simple-shm + +[ivi-launcher] +workspace-id=2 +icon-id=4005 +icon=@abs_top_srcdir@/data/icon_ivi_smoke.png +path=@abs_top_builddir@/weston-smoke + +[ivi-launcher] +workspace-id=3 +icon-id=4006 +icon=@abs_top_srcdir@/data/icon_ivi_flower.png +path=@abs_top_builddir@/weston-flower + +[ivi-launcher] +workspace-id=3 +icon-id=4007 +icon=@abs_top_srcdir@/data/icon_ivi_clickdot.png +path=@abs_top_builddir@/weston-clickdot + +[ivi-launcher] +workspace-id=3 +icon-id=4008 +icon=@abs_top_srcdir@/data/icon_ivi_simple-egl.png +path=@abs_top_builddir@/weston-simple-egl + +[ivi-launcher] +workspace-id=3 +icon-id=4009 +icon=@abs_top_srcdir@/data/icon_ivi_simple-shm.png +path=@abs_top_builddir@/weston-simple-shm + +[ivi-launcher] +workspace-id=3 +icon-id=4010 +icon=@abs_top_srcdir@/data/icon_ivi_smoke.png +path=@abs_top_builddir@/weston-smoke diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml new file mode 100644 index 0000000..8f24226 --- /dev/null +++ b/protocol/ivi-application.xml @@ -0,0 +1,100 @@ + + + + + Copyright (C) 2013 DENSO CORPORATION + Copyright (c) 2013 BMW Car IT GmbH + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + + + + This removes link from ivi_id to wl_surface and destroys ivi_surface. + The ID, ivi_id, is free and can be used for surface_create again. + + + + + + The configure event asks the client to resize its surface. + + The size is a hint, in the sense that the client is free to + ignore it if it doesn't resize, pick a smaller size (to + satisfy aspect ratio or resize in steps of NxM pixels). + + The client is free to dismiss all but the last configure + event it received. + + The width and height arguments specify the size of the window + in surface local coordinates. + + + + + + + + + This interface is exposed as a global singleton. + This interface is implemented by servers that provide IVI-style user interfaces. + It allows clients to associate a ivi_surface with wl_surface. + + + + + + + + + + This request gives the wl_surface the role of an IVI Surface. Creating more than + one ivi_surface for a wl_surface is not allowed. Note, that this still allows the + following example: + + 1. create a wl_surface + 2. create ivi_surface for the wl_surface + 3. destroy the ivi_surface + 4. create ivi_surface for the wl_surface (with the same or another ivi_id as before) + + surface_create will create a interface:ivi_surface with numeric ID; ivi_id in + ivi compositor. These ivi_ids are defined as unique in the system to identify + it inside of ivi compositor. The ivi compositor implements business logic how to + set properties of the surface with ivi_id according to status of the system. + E.g. a unique ID for Car Navigation application is used for implementing special + logic of the application about where it shall be located. + The server regards following cases as protocol errors and disconnects the client. + - wl_surface already has an nother role. + - ivi_id is already assigned to an another wl_surface. + + If client destroys ivi_surface or wl_surface which is assigne to the ivi_surface, + ivi_id which is assigned to the ivi_surface is free for reuse. + + + + + + + + + diff --git a/protocol/ivi-hmi-controller.xml b/protocol/ivi-hmi-controller.xml new file mode 100644 index 0000000..826763c --- /dev/null +++ b/protocol/ivi-hmi-controller.xml @@ -0,0 +1,98 @@ + + + + + Copyright (C) 2013 DENSO CORPORATION + Copyright (c) 2013 BMW Car IT GmbH + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + + + + + + + + Reference protocol to control a surface by server. + To control a surface by server, it gives seat to the server + to e.g. control Home screen. Home screen has several workspaces + to group launchers of wayland application. These workspaces + are drawn on a horizontally long surface to be controlled + by motion of input device. E.g. A motion from right to left + happens, the viewport of surface is controlled in the ivi-shell + by using ivi-layout. client can recognizes the end of controlling + by event "workspace_end_control". + + + + + + + + + + + + + + + hmi-controller loaded to ivi-shall implements 4 types of layout + as a reference; tiling, side by side, full_screen, and random. + + + + + + + + + + + + home screen is a reference implementation of launcher to launch + wayland applications. The home screen has several workspaces to + group wayland applications. By defining the following keys in + weston.ini, user can add launcher icon to launch a wayland application + to a workspace. + [ivi-launcher] + workspace-id=0 + : id of workspace to add a launcher + icon-id=4001 + : ivi id of ivi_surface to draw a icon + icon=/home/user/review/build-ivi-shell/data/icon_ivi_flower.png + : path to icon image + path=/home/user/review/build-ivi-shell/weston-dnd + : path to wayland application + + + + + + + + + + + + diff --git a/shared/helpers.h b/shared/helpers.h new file mode 100644 index 0000000..1d1e458 --- /dev/null +++ b/shared/helpers.h @@ -0,0 +1,96 @@ +/* + * Copyright © 2015 Samsung Electronics Co., 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 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_HELPERS_H +#define WESTON_HELPERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * Simple misc helper macros. + */ + +/** + * Compile-time computation of number of items in a hardcoded array. + * + * @param a the array being measured. + * @return the number of items hardcoded into the array. + */ +#ifndef ARRAY_LENGTH +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) +#endif + +/** + * Returns the smaller of two values. + * + * @param x the first item to compare. + * @param y the second item to compare. + * @return the value that evaluates to lesser than the other. + */ +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + +/** + * Returns a pointer the the containing struct of a given member item. + * + * To demonstrate, the following example retrieves a pointer to + * `example_container` given only its `destroy_listener` member: + * + * @code + * struct example_container { + * struct wl_listener destroy_listener; + * // other members... + * }; + * + * void example_container_destroy(struct wl_listener *listener, void *data) + * { + * struct example_container *ctr; + * + * ctr = wl_container_of(listener, ctr, destroy_listener); + * // destroy ctr... + * } + * @endcode + * + * @param ptr A valid pointer to the contained item. + * + * @param type A pointer to the type of content that the list item + * stores. Type does not need be a valid pointer; a null or + * an uninitialised pointer will suffice. + * + * @param member The named location of ptr within the sample type. + * + * @return The container for the specified pointer. + */ +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* WESTON_HELPERS_H */ diff --git a/src/compositor.c b/src/compositor.c index 574db2d..e9c46a4 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -2503,6 +2503,54 @@ weston_surface_get_main_surface(struct weston_surface *surface) return surface; } +/** Get the size of surface contents */ +WL_EXPORT void +weston_surface_get_content_size(struct weston_surface *surface, + int *width, int *height) +{ + struct weston_renderer *rer = surface->compositor->renderer; + + if (!rer->surface_get_content_size) { + *width = 0; + *height = 0; + return; + } + + rer->surface_get_content_size(surface, width, height); +} + +/** Copy surface contents to system memory */ +WL_EXPORT int +weston_surface_copy_content(struct weston_surface *surface, + void *target, size_t size, + int src_x, int src_y, + int width, int height) +{ + struct weston_renderer *rer = surface->compositor->renderer; + int cw, ch; + const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */ + + if (!rer->surface_copy_content) + return -1; + + weston_surface_get_content_size(surface, &cw, &ch); + + if (src_x < 0 || src_y < 0) + return -1; + + if (width <= 0 || height <= 0) + return -1; + + if (src_x + width > cw || src_y + height > ch) + return -1; + + if (width * bytespp * height > size) + return -1; + + return rer->surface_copy_content(surface, target, size, + src_x, src_y, width, height); +} + static void subsurface_set_position(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) diff --git a/src/compositor.h b/src/compositor.h index 057f8be..2a8da6b 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -552,6 +552,16 @@ struct weston_renderer { float red, float green, float blue, float alpha); void (*destroy)(struct weston_compositor *ec); + + /** See weston_surface_get_content_size() */ + void (*surface_get_content_size)(struct weston_surface *surface, + int *width, int *height); + + /** See weston_surface__copy_content() */ + int (*surface_copy_content)(struct weston_surface *surface, + void *target, size_t size, + int src_x, int src_y, + int width, int height); }; enum weston_capability { @@ -1205,6 +1215,16 @@ weston_surface_unmap(struct weston_surface *surface); struct weston_surface * weston_surface_get_main_surface(struct weston_surface *surface); +void +weston_surface_get_content_size(struct weston_surface *surface, + int *width, int *height); + +int +weston_surface_copy_content(struct weston_surface *surface, + void *target, size_t size, + int src_x, int src_y, + int width, int height); + struct weston_buffer * weston_buffer_from_resource(struct wl_resource *resource); diff --git a/src/gl-renderer.c b/src/gl-renderer.c index 63af75d..55b612c 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -77,6 +77,7 @@ struct gl_output_state { enum buffer_type { BUFFER_TYPE_NULL, + BUFFER_TYPE_SOLID, /* internal solid color surfaces without a buffer */ BUFFER_TYPE_SHM, BUFFER_TYPE_EGL }; @@ -1297,11 +1298,157 @@ gl_renderer_surface_set_color(struct weston_surface *surface, gs->color[1] = green; gs->color[2] = blue; gs->color[3] = alpha; + gs->buffer_type = BUFFER_TYPE_SOLID; gs->shader = &gr->solid_shader; } static void +gl_renderer_surface_get_content_size(struct weston_surface *surface, + int *width, int *height) +{ + struct gl_surface_state *gs = get_surface_state(surface); + + if (gs->buffer_type == BUFFER_TYPE_NULL) { + *width = 0; + *height = 0; + } else { + *width = gs->pitch; + *height = gs->height; + } +} + +static uint32_t +pack_color(pixman_format_code_t format, float *c) +{ + uint8_t r = round(c[0] * 255.0f); + uint8_t g = round(c[1] * 255.0f); + uint8_t b = round(c[2] * 255.0f); + uint8_t a = round(c[3] * 255.0f); + + switch (format) { + case PIXMAN_a8b8g8r8: + return (a << 24) | (b << 16) | (g << 8) | r; + default: + assert(0); + return 0; + } +} + +static int +gl_renderer_surface_copy_content(struct weston_surface *surface, + void *target, size_t size, + int src_x, int src_y, + int width, int height) +{ + static const GLfloat verts[4 * 2] = { + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f + }; + static const GLfloat projmat_normal[16] = { /* transpose */ + 2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, 1.0f + }; + static const GLfloat projmat_yinvert[16] = { /* transpose */ + 2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 1.0f + }; + const pixman_format_code_t format = PIXMAN_a8b8g8r8; + const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */ + const GLenum gl_format = GL_RGBA; /* PIXMAN_a8b8g8r8 little-endian */ + struct gl_renderer *gr = get_renderer(surface->compositor); + struct gl_surface_state *gs = get_surface_state(surface); + int cw, ch; + GLuint fbo; + GLuint tex; + GLenum status; + const GLfloat *proj; + int i; + + gl_renderer_surface_get_content_size(surface, &cw, &ch); + + switch (gs->buffer_type) { + case BUFFER_TYPE_NULL: + return -1; + case BUFFER_TYPE_SOLID: + *(uint32_t *)target = pack_color(format, gs->color); + return 0; + case BUFFER_TYPE_SHM: + gl_renderer_flush_damage(surface); + /* fall through */ + case BUFFER_TYPE_EGL: + break; + } + + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cw, ch, + 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tex, 0); + + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + weston_log("%s: fbo error: %#x\n", __func__, status); + glDeleteFramebuffers(1, &fbo); + glDeleteTextures(1, &tex); + return -1; + } + + glViewport(0, 0, cw, ch); + glDisable(GL_BLEND); + use_shader(gr, gs->shader); + if (gs->y_inverted) + proj = projmat_normal; + else + proj = projmat_yinvert; + + glUniformMatrix4fv(gs->shader->proj_uniform, 1, GL_FALSE, proj); + glUniform1f(gs->shader->alpha_uniform, 1.0f); + + for (i = 0; i < gs->num_textures; i++) { + glUniform1i(gs->shader->tex_uniforms[i], i); + + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(gs->target, gs->textures[i]); + glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + /* position: */ + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); + glEnableVertexAttribArray(0); + + /* texcoord: */ + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, verts); + glEnableVertexAttribArray(1); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + + glPixelStorei(GL_PACK_ALIGNMENT, bytespp); + glReadPixels(src_x, src_y, width, height, gl_format, + GL_UNSIGNED_BYTE, target); + + glDeleteFramebuffers(1, &fbo); + glDeleteTextures(1, &tex); + + return 0; +} + +static void surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr) { int i; @@ -1932,6 +2079,9 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display, gr->base.attach = gl_renderer_attach; gr->base.surface_set_color = gl_renderer_surface_set_color; gr->base.destroy = gl_renderer_destroy; + gr->base.surface_get_content_size = + gl_renderer_surface_get_content_size; + gr->base.surface_copy_content = gl_renderer_surface_copy_content; gr->egl_display = eglGetDisplay(display); if (gr->egl_display == EGL_NO_DISPLAY) { diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c index 93be968..c9d5038 100644 --- a/src/pixman-renderer.c +++ b/src/pixman-renderer.c @@ -674,6 +674,53 @@ pixman_renderer_destroy(struct weston_compositor *ec) } static void +pixman_renderer_surface_get_content_size(struct weston_surface *surface, + int *width, int *height) +{ + struct pixman_surface_state *ps = get_surface_state(surface); + + if (ps->image) { + *width = pixman_image_get_width(ps->image); + *height = pixman_image_get_height(ps->image); + } else { + *width = 0; + *height = 0; + } +} + +static int +pixman_renderer_surface_copy_content(struct weston_surface *surface, + void *target, size_t size, + int src_x, int src_y, + int width, int height) +{ + const pixman_format_code_t format = PIXMAN_a8b8g8r8; + const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */ + struct pixman_surface_state *ps = get_surface_state(surface); + pixman_image_t *out_buf; + + if (!ps->image) + return -1; + + out_buf = pixman_image_create_bits(format, width, height, + target, width * bytespp); + + pixman_image_set_transform(ps->image, NULL); + pixman_image_composite32(PIXMAN_OP_SRC, + ps->image, /* src */ + NULL, /* mask */ + out_buf, /* dest */ + src_x, src_y, /* src_x, src_y */ + 0, 0, /* mask_x, mask_y */ + 0, 0, /* dest_x, dest_y */ + width, height); + + pixman_image_unref(out_buf); + + return 0; +} + +static void debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data) { @@ -711,6 +758,10 @@ pixman_renderer_init(struct weston_compositor *ec) renderer->base.attach = pixman_renderer_attach; renderer->base.surface_set_color = pixman_renderer_surface_set_color; renderer->base.destroy = pixman_renderer_destroy; + renderer->base.surface_get_content_size = + pixman_renderer_surface_get_content_size; + renderer->base.surface_copy_content = + pixman_renderer_surface_copy_content; ec->renderer = &renderer->base; ec->capabilities |= WESTON_CAP_ROTATION_ANY; ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP; -- 1.8.3.1