/* * 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 "config.h" #include #include #include #include #include #include #include "ivi-shell.h" #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; /* ivi_layout::pending_transition_list * ivi_layout_transition_set::transition_list */ 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; } void ivi_layout_remove_all_surface_transitions(struct ivi_layout_surface *surface) { struct ivi_layout *layout = get_instance(); struct transition_node *node; struct transition_node *tmp; struct ivi_layout_transition *tran; wl_list_for_each_safe(node, tmp, &layout->transitions->transition_list, link) { tran = node->transition; if (tran->is_transition_func(tran->private_data, surface)) { layout_transition_destroy(tran); } }; } 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 bool 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 false; } node->transition = trans; wl_list_insert(&layout->pending_transition_list, &node->link); return true; } 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->is_transition_func = NULL; 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; ivi_layout_surface_set_size(layout_surface, layout_surface->prop.dest_width, layout_surface->prop.dest_height); 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__); free(transition); 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); if (transition && layout_transition_register(transition)) return; layout_transition_destroy(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__); free(transition); 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); if (transition && layout_transition_register(transition)) return; layout_transition_destroy(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 = surface->prop.visibility; wl_fixed_t dest_alpha = surface->prop.opacity; 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 = surface->prop.opacity; 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 = surface->prop.opacity; 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_destination_rectangle(layer, dest_x, dest_y, layer->prop.dest_width, layer->prop.dest_height); } 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__); free(transition); 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 = layer->prop.dest_x; int32_t start_pos_y = layer->prop.dest_y; struct ivi_layout_transition *transition = NULL; transition = create_move_layer_transition( layer, start_pos_x, start_pos_y, dest_x, dest_y, NULL, NULL, duration); if (transition && layout_transition_register(transition)) return; free(transition); } 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; wl_fixed_t fixed_opacity; double now_opacity; double remain; transition = get_transition_from_type_and_id( IVI_LAYOUT_TRANSITION_LAYER_FADE, layer); if (transition) { /* transition update */ data = transition->private_data; /* FIXME */ fixed_opacity = layer->prop.opacity; now_opacity = wl_fixed_to_double(fixed_opacity); 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__); free(transition); 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; if (!layout_transition_register(transition)) layout_transition_destroy(transition); return; }