weston/ivi-shell/ivi-layout.c
Ucan, Emre (ADITG/SW1) c98f2cf16b ivi-shell: rework create_layer_notification
The add_notification_layer_surface API accepts a simple
wl_listener instead of a ivi-shell specific notification
function. Therefore, the API is renamed to add_listener_layer_surface.

This change has several advantages:
1. Code cleanup
2. No dynamic memory allocation. Listeners are allocated
   by controller plugins
3. Remove API is not needed. Controller plugins can easily
   remove the listener link.

The remove API is removed too:
- ivi_layout_remove_notification_create_layer

Signed-off-by: Emre Ucan <eucan@de.adit-jv.com>
Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
2016-04-05 11:53:48 +03:00

2262 lines
61 KiB
C

/*
* 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 <string.h>
#include <assert.h>
#include "compositor.h"
#include "ivi-shell.h"
#include "ivi-layout-export.h"
#include "ivi-layout-private.h"
#include "ivi-layout-shell.h"
#include "shared/helpers.h"
#include "shared/os-compatibility.h"
#define max(a, b) ((a) > (b) ? (a) : (b))
struct listener_layout_notification {
void *userdata;
struct wl_listener listener;
};
struct ivi_layout;
struct ivi_layout_screen {
struct wl_list link;
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 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 struct weston_view *
get_weston_view(struct ivi_layout_surface *ivisurf)
{
struct weston_view *view = NULL;
assert(ivisurf->surface != NULL);
/* One view per surface */
if(wl_list_empty(&ivisurf->surface->views))
view = NULL;
else
view = wl_container_of(ivisurf->surface->views.next, view, surface_link);
return view;
}
static struct ivi_layout_screen *
get_screen_from_output(struct weston_output *output)
{
struct ivi_layout *layout = get_instance();
struct ivi_layout_screen *iviscrn = NULL;
wl_list_for_each(iviscrn, &layout->screen_list, link) {
if (iviscrn->output == output)
return iviscrn;
}
return NULL;
}
/**
* 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);
wl_signal_emit(&layout->surface_notification.removed, ivisurf);
ivi_layout_remove_all_surface_transitions(ivisurf);
free(ivisurf);
}
/**
* 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;
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->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_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)
{
struct weston_view *tmpview = NULL;
double layer_alpha = wl_fixed_to_double(ivilayer->prop.opacity);
double surf_alpha = wl_fixed_to_double(ivisurf->prop.opacity);
tmpview = get_weston_view(ivisurf);
assert(tmpview != NULL);
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 multi screens coordinate, which is 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 tansformed to multi screen coordinate,
* global coordinates. This is done by adding weston_output.{x,y} in simple
* because there is no scaled and rotated transformation.
* - destination rectangle of layer in multi screens coordinate needs to be
* intersected inside of a screen the layer is assigned to. This is because
* overlapped region of weston surface in another screen shall not be
* displayed according to ivi use case.
* - destination rectangle of layer
* - in multi screen coordinates,
* - and intersected inside of an assigned screen,
* 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_screen *iviscrn,
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 weston_output *output = iviscrn->output;
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 screen_dest_rect = { output->x,
output->y,
output->width,
output->height };
struct ivi_rectangle layer_dest_rect_in_global =
{ lp->dest_x + output->x,
lp->dest_y + output->y,
lp->dest_width,
lp->dest_height };
struct ivi_rectangle surface_result;
struct ivi_rectangle layer_dest_rect_in_global_intersected;
/*
* 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 a single screen-local coordinates
* - a single screen-local coordinates to multi screen coordinates,
* which is 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);
weston_matrix_translate(m, output->x, output->y, 0.0f);
/* this intersected ivi_rectangle would be used for masking
* weston_surface
*/
ivi_rectangle_intersect(&surface_source_rect, &weston_surface_rect,
&surface_result);
/*
* destination rectangle of layer in multi screens coordinate
* is intersected to avoid displaying outside of an assigned screen.
*/
ivi_rectangle_intersect(&layer_dest_rect_in_global, &screen_dest_rect,
&layer_dest_rect_in_global_intersected);
/* calc masking area of weston_surface from m */
calc_inverse_matrix_transform(m,
&layer_dest_rect_in_global_intersected,
&surface_result,
result);
}
static void
update_prop(struct ivi_layout_screen *iviscrn,
struct ivi_layout_layer *ivilayer,
struct ivi_layout_surface *ivisurf)
{
struct weston_view *tmpview;
struct ivi_rectangle r;
bool can_calc = true;
/*In case of no prop change, this just returns*/
if (!ivilayer->prop.event_mask && !ivisurf->prop.event_mask)
return;
update_opacity(ivilayer, ivisurf);
tmpview = get_weston_view(ivisurf);
assert(tmpview != NULL);
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(
iviscrn, ivilayer, ivisurf, &ivisurf->transform.matrix, &r);
weston_view_set_mask(tmpview, r.x, r.y, r.width, r.height);
wl_list_insert(&tmpview->geometry.transformation_list,
&ivisurf->transform.link);
weston_view_set_transform_parent(tmpview, NULL);
}
ivisurf->update_count++;
weston_view_geometry_dirty(tmpview);
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) {
/*
* If ivilayer is invisible, weston_view of ivisurf doesn't
* need to be modified.
*/
if (ivilayer->prop.visibility == false)
continue;
wl_list_for_each(ivisurf, &ivilayer->order.surface_list, order.link) {
/*
* If ivilayer is invisible, weston_view of ivisurf doesn't
* need to be modified.
*/
if (ivisurf->prop.visibility == false)
continue;
update_prop(iviscrn, 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)) {
shell_surface_send_configure(ivisurf->surface,
ivisurf->prop.dest_width,
ivisurf->prop.dest_height);
}
} 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)) {
shell_surface_send_configure(ivisurf->surface,
ivisurf->prop.dest_width,
ivisurf->prop.dest_height);
}
}
}
}
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) {
ivisurf->on_layer = NULL;
wl_list_remove(&ivisurf->order.link);
wl_list_init(&ivisurf->order.link);
ivisurf->prop.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);
ivisurf->on_layer = ivilayer;
ivisurf->prop.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;
struct weston_view *tmpview = NULL;
/* Clear view list of layout ivi_layer */
wl_list_init(&layout->layout_layer.view_list.link);
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) {
ivilayer->on_screen = NULL;
wl_list_remove(&ivilayer->order.link);
wl_list_init(&ivilayer->order.link);
ivilayer->prop.event_mask |= IVI_NOTIFICATION_REMOVE;
}
assert(wl_list_empty(&iviscrn->order.layer_list));
wl_list_for_each(ivilayer, &iviscrn->pending.layer_list,
pending.link) {
/* FIXME: avoid to insert order.link to multiple screens */
wl_list_remove(&ivilayer->order.link);
wl_list_insert(&iviscrn->order.layer_list,
&ivilayer->order.link);
ivilayer->on_screen = iviscrn;
ivilayer->prop.event_mask |= IVI_NOTIFICATION_ADD;
}
iviscrn->order.dirty = 0;
}
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) {
if (ivisurf->prop.visibility == false)
continue;
tmpview = get_weston_view(ivisurf);
assert(tmpview != NULL);
weston_layer_entry_insert(&layout->layout_layer.view_list,
&tmpview->layer_link);
ivisurf->surface->output = iviscrn->output;
}
}
}
}
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->pending.prop.event_mask = 0;
}
static void
send_layer_prop(struct ivi_layout_layer *ivilayer)
{
wl_signal_emit(&ivilayer->property_changed, ivilayer);
ivilayer->pending.prop.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->prop.event_mask)
send_layer_prop(ivilayer);
}
wl_list_for_each_reverse(ivisurf, &layout->surface_list, link) {
if (ivisurf->prop.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_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
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_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, &notification->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_listener_create_layer(struct wl_listener *listener)
{
struct ivi_layout *layout = get_instance();
if (listener == NULL) {
weston_log("ivi_layout_add_listener_create_layer: invalid argument\n");
return IVI_FAILED;
}
wl_signal_add(&layout->layer_notification.created, listener);
return IVI_SUCCEEDED;
}
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_listener_create_surface(struct wl_listener *listener)
{
struct ivi_layout *layout = get_instance();
if (listener == NULL) {
weston_log("ivi_layout_add_listener_create_surface: invalid argument\n");
return IVI_FAILED;
}
wl_signal_add(&layout->surface_notification.created, listener);
return IVI_SUCCEEDED;
}
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 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 int32_t
ivi_layout_surface_add_listener(struct ivi_layout_surface *ivisurf,
struct wl_listener *listener)
{
if (ivisurf == NULL || listener == NULL) {
weston_log("ivi_layout_surface_add_listener: invalid argument\n");
return IVI_FAILED;
}
wl_signal_add(&ivisurf->property_changed, 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_under_layer(struct ivi_layout_layer *ivilayer,
int32_t *pLength,
struct weston_output ***ppArray)
{
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;
}
if (ivilayer->on_screen != NULL)
length = 1;
if (length != 0) {
/* the Array must be free by module which called this function */
*ppArray = calloc(length, sizeof(struct weston_output *));
if (*ppArray == NULL) {
weston_log("fails to allocate memory\n");
return IVI_FAILED;
}
(*ppArray)[n++] = ivilayer->on_screen->output;
}
*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 weston_output *output,
int32_t *pLength,
struct ivi_layout_layer ***ppArray)
{
struct ivi_layout_screen *iviscrn = NULL;
struct ivi_layout_layer *ivilayer = NULL;
int32_t length = 0;
int32_t n = 0;
if (output == NULL || pLength == NULL || ppArray == NULL) {
weston_log("ivi_layout_get_layers_on_screen: invalid argument\n");
return IVI_FAILED;
}
iviscrn = get_screen_from_output(output);
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)
{
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;
}
if (ivisurf->on_layer != NULL) {
/* the Array must be free by module which called this function */
length = 1;
*ppArray = calloc(length, sizeof(struct ivi_layout_screen *));
if (*ppArray == NULL) {
weston_log("fails to allocate memory\n");
return IVI_FAILED;
}
(*ppArray)[n++] = ivisurf->on_layer;
}
*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);
ivilayer->layout = layout;
ivilayer->id_layer = id_layer;
init_layer_properties(&ivilayer->prop, width, height);
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_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);
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)
prop->event_mask |= IVI_NOTIFICATION_VISIBILITY;
else
prop->event_mask &= ~IVI_NOTIFICATION_VISIBILITY;
return IVI_SUCCEEDED;
}
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)
prop->event_mask |= IVI_NOTIFICATION_OPACITY;
else
prop->event_mask &= ~IVI_NOTIFICATION_OPACITY;
return IVI_SUCCEEDED;
}
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)
prop->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
else
prop->event_mask &= ~IVI_NOTIFICATION_SOURCE_RECT;
return IVI_SUCCEEDED;
}
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)
prop->event_mask |= IVI_NOTIFICATION_DEST_RECT;
else
prop->event_mask &= ~IVI_NOTIFICATION_DEST_RECT;
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)
prop->event_mask |= IVI_NOTIFICATION_ORIENTATION;
else
prop->event_mask &= ~IVI_NOTIFICATION_ORIENTATION;
return IVI_SUCCEEDED;
}
int32_t
ivi_layout_layer_set_render_order(struct ivi_layout_layer *ivilayer,
struct ivi_layout_surface **pSurface,
int32_t number)
{
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++) {
wl_list_remove(&pSurface[i]->pending.link);
wl_list_insert(&ivilayer->pending.surface_list,
&pSurface[i]->pending.link);
}
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)
prop->event_mask |= IVI_NOTIFICATION_VISIBILITY;
else
prop->event_mask &= ~IVI_NOTIFICATION_VISIBILITY;
return IVI_SUCCEEDED;
}
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)
prop->event_mask |= IVI_NOTIFICATION_OPACITY;
else
prop->event_mask &= ~IVI_NOTIFICATION_OPACITY;
return IVI_SUCCEEDED;
}
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)
prop->event_mask |= IVI_NOTIFICATION_DEST_RECT;
else
prop->event_mask &= ~IVI_NOTIFICATION_DEST_RECT;
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)
prop->event_mask |= IVI_NOTIFICATION_ORIENTATION;
else
prop->event_mask &= ~IVI_NOTIFICATION_ORIENTATION;
return IVI_SUCCEEDED;
}
static int32_t
ivi_layout_screen_add_layer(struct weston_output *output,
struct ivi_layout_layer *addlayer)
{
struct ivi_layout_screen *iviscrn;
if (output == NULL || addlayer == NULL) {
weston_log("ivi_layout_screen_add_layer: invalid argument\n");
return IVI_FAILED;
}
iviscrn = get_screen_from_output(output);
if (addlayer->on_screen == iviscrn) {
weston_log("ivi_layout_screen_add_layer: addlayer is already available\n");
return IVI_SUCCEEDED;
}
wl_list_remove(&addlayer->pending.link);
wl_list_insert(&iviscrn->pending.layer_list, &addlayer->pending.link);
iviscrn->order.dirty = 1;
return IVI_SUCCEEDED;
}
static int32_t
ivi_layout_screen_set_render_order(struct weston_output *output,
struct ivi_layout_layer **pLayer,
const int32_t number)
{
struct ivi_layout_screen *iviscrn;
struct ivi_layout_layer *ivilayer = NULL;
struct ivi_layout_layer *next = NULL;
int32_t i = 0;
if (output == NULL) {
weston_log("ivi_layout_screen_set_render_order: invalid argument\n");
return IVI_FAILED;
}
iviscrn = get_screen_from_output(output);
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++) {
wl_list_remove(&pLayer[i]->pending.link);
wl_list_insert(&iviscrn->pending.layer_list,
&pLayer[i]->pending.link);
}
iviscrn->order.dirty = 1;
return IVI_SUCCEEDED;
}
/**
* 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_listener(struct ivi_layout_layer *ivilayer,
struct wl_listener *listener)
{
if (ivilayer == NULL || listener == NULL) {
weston_log("ivi_layout_layer_add_listener: invalid argument\n");
return IVI_FAILED;
}
wl_signal_add(&ivilayer->property_changed, listener);
return IVI_SUCCEEDED;
}
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)
{
if (ivilayer == NULL || addsurf == NULL) {
weston_log("ivi_layout_layer_add_surface: invalid argument\n");
return IVI_FAILED;
}
if (addsurf->on_layer == ivilayer)
return IVI_SUCCEEDED;
wl_list_remove(&addsurf->pending.link);
wl_list_insert(&ivilayer->pending.surface_list, &addsurf->pending.link);
ivilayer->order.dirty = 1;
return IVI_SUCCEEDED;
}
static void
ivi_layout_layer_remove_surface(struct ivi_layout_layer *ivilayer,
struct ivi_layout_surface *remsurf)
{
if (ivilayer == NULL || remsurf == NULL) {
weston_log("ivi_layout_layer_remove_surface: invalid argument\n");
return;
}
wl_list_remove(&remsurf->pending.link);
wl_list_init(&remsurf->pending.link);
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)
prop->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
else
prop->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)
{
if (surface == NULL)
return NULL;
return get_weston_view(surface);
}
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);
}
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);
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->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);
}
static struct ivi_layout_interface ivi_layout_interface = {
/**
* commit all changes
*/
.commit_changes = ivi_layout_commit_changes,
/**
* surface controller interfaces
*/
.add_listener_create_surface = ivi_layout_add_listener_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_set_opacity = ivi_layout_surface_set_opacity,
.surface_set_source_rectangle = ivi_layout_surface_set_source_rectangle,
.surface_set_destination_rectangle = ivi_layout_surface_set_destination_rectangle,
.surface_set_orientation = ivi_layout_surface_set_orientation,
.surface_add_listener = ivi_layout_surface_add_listener,
.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_listener_create_layer = ivi_layout_add_listener_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_set_opacity = ivi_layout_layer_set_opacity,
.layer_set_source_rectangle = ivi_layout_layer_set_source_rectangle,
.layer_set_destination_rectangle = ivi_layout_layer_set_destination_rectangle,
.layer_set_orientation = ivi_layout_layer_set_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_listener = ivi_layout_layer_add_listener,
.layer_set_transition = ivi_layout_layer_set_transition,
/**
* screen controller interfaces
*/
.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,
/**
* 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,
};
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_layout_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_layout_interface,
sizeof(struct ivi_layout_interface)) != 0) {
weston_log("ivi-shell: Initialization of controller module fails");
return -1;
}
p = end;
while (*p == ',')
p++;
}
return 0;
}