Use timers for animations (compositor, desktop)
Yutani, glogin, and wallpaper now use timing information from the kernel to perform animations. Some animation lengths have been adjusted. The animations should run at the same speed, though with varying "smoothness" across different hardware (including non-KVM emulators).
This commit is contained in:
parent
7344a50fe0
commit
278059d6a2
@ -16,6 +16,7 @@
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
@ -125,6 +126,29 @@ static int next_wid(void) {
|
||||
return _next++;
|
||||
}
|
||||
|
||||
static uint32_t yutani_current_time(yutani_globals_t * yg) {
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
|
||||
uint32_t sec_diff = t.tv_sec - yg->start_time;
|
||||
uint32_t usec_diff = t.tv_usec - yg->start_subtime;
|
||||
|
||||
if (t.tv_usec < yg->start_subtime) {
|
||||
sec_diff -= 1;
|
||||
usec_diff = (1000000 + t.tv_usec) - yg->start_subtime;
|
||||
}
|
||||
|
||||
return (uint32_t)(sec_diff * 1000 + usec_diff / 1000);
|
||||
}
|
||||
|
||||
static uint32_t yutani_time_since(yutani_globals_t * yg, uint32_t start_time) {
|
||||
|
||||
uint32_t now = yutani_current_time(yg);
|
||||
uint32_t diff = now - start_time; /* Milliseconds */
|
||||
|
||||
return diff / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate and transform coordinate from screen-relative to window-relative.
|
||||
*/
|
||||
@ -337,7 +361,7 @@ static yutani_server_window_t * server_window_create(yutani_globals_t * yg, int
|
||||
win->client_length = 0;
|
||||
win->client_strings = NULL;
|
||||
win->anim_mode = YUTANI_EFFECT_FADE_IN;
|
||||
win->anim_start = yg->tick_count;
|
||||
win->anim_start = yutani_current_time(yg);
|
||||
win->alpha_threshold = 0;
|
||||
win->show_mouse = 1;
|
||||
|
||||
@ -771,7 +795,7 @@ static int yutani_blit_window(yutani_globals_t * yg, cairo_t * ctx, yutani_serve
|
||||
}
|
||||
}
|
||||
if (window->anim_mode) {
|
||||
int frame = yg->tick_count - window->anim_start;
|
||||
int frame = yutani_time_since(yg, window->anim_start);
|
||||
if (frame >= yutani_animation_lengths[window->anim_mode]) {
|
||||
/* XXX handle animation-end things like cleanup of closing windows */
|
||||
if (window->anim_mode == YUTANI_EFFECT_FADE_OUT) {
|
||||
@ -785,11 +809,12 @@ static int yutani_blit_window(yutani_globals_t * yg, cairo_t * ctx, yutani_serve
|
||||
switch (window->anim_mode) {
|
||||
case YUTANI_EFFECT_FADE_OUT:
|
||||
{
|
||||
frame = 256 - frame;
|
||||
frame = yutani_animation_lengths[window->anim_mode] - frame;
|
||||
}
|
||||
case YUTANI_EFFECT_FADE_IN:
|
||||
{
|
||||
double x = 0.75 + ((double)frame / 256.0) * 0.25;
|
||||
double time_diff = ((double)frame / (float)yutani_animation_lengths[window->anim_mode]);
|
||||
double x = 0.75 + time_diff * 0.25;
|
||||
int t_x = (window->width * (1.0 - x)) / 2;
|
||||
int t_y = (window->height * (1.0 - x)) / 2;
|
||||
|
||||
@ -800,7 +825,7 @@ static int yutani_blit_window(yutani_globals_t * yg, cairo_t * ctx, yutani_serve
|
||||
|
||||
cairo_set_source_surface(cr, surf, 0, 0);
|
||||
cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST);
|
||||
cairo_paint_with_alpha(cr, (double)frame/256.0);
|
||||
cairo_paint_with_alpha(cr, time_diff);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -973,8 +998,6 @@ static void redraw_windows(yutani_globals_t * yg) {
|
||||
yg->last_mouse_x = tmp_mouse_x;
|
||||
yg->last_mouse_y = tmp_mouse_y;
|
||||
|
||||
yg->tick_count += 10;
|
||||
|
||||
if (yg->bottom_z && yg->bottom_z->anim_mode) mark_window(yg, yg->bottom_z);
|
||||
if (yg->top_z && yg->top_z->anim_mode) mark_window(yg, yg->top_z);
|
||||
foreach (node, yg->mid_zs) {
|
||||
@ -1191,7 +1214,7 @@ static void mark_window(yutani_globals_t * yg, yutani_server_window_t * window)
|
||||
*/
|
||||
static void window_mark_for_close(yutani_globals_t * yg, yutani_server_window_t * w) {
|
||||
w->anim_mode = YUTANI_EFFECT_FADE_OUT;
|
||||
w->anim_start = yg->tick_count;
|
||||
w->anim_start = yutani_current_time(yg);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1711,6 +1734,13 @@ int main(int argc, char * argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
yg->start_time = t.tv_sec;
|
||||
yg->start_subtime = t.tv_usec;
|
||||
}
|
||||
|
||||
yg->width = yg->backend_ctx->width;
|
||||
yg->height = yg->backend_ctx->height;
|
||||
|
||||
|
@ -59,7 +59,7 @@ typedef struct {
|
||||
char * client_strings;
|
||||
|
||||
int anim_mode;
|
||||
int anim_start;
|
||||
uint32_t anim_start;
|
||||
|
||||
int alpha_threshold;
|
||||
int show_mouse;
|
||||
@ -123,7 +123,7 @@ typedef struct {
|
||||
|
||||
list_t * window_subscribers;
|
||||
|
||||
int tick_count;
|
||||
uint32_t start_time;
|
||||
|
||||
volatile int redraw_lock;
|
||||
|
||||
@ -143,6 +143,8 @@ typedef struct {
|
||||
|
||||
int screenshot_frame;
|
||||
|
||||
uint32_t start_subtime;
|
||||
|
||||
} yutani_globals_t;
|
||||
|
||||
struct key_bind {
|
||||
|
@ -230,6 +230,12 @@ void draw_login_container(cairo_t * cr, struct login_container * lc) {
|
||||
|
||||
}
|
||||
|
||||
#define _app_name "glogin"
|
||||
#define TRACE(msg,...) do { \
|
||||
struct timeval t; gettimeofday(&t, NULL); \
|
||||
fprintf(stderr, "%06d.%06d [" _app_name "] %s:%05d - " msg "\n", t.tv_sec, t.tv_usec, __FILE__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
init_shmemfonts();
|
||||
|
||||
@ -262,13 +268,14 @@ int main (int argc, char ** argv) {
|
||||
WALLPAPER = confreader_getd(conf, "image", "wallpaper", WALLPAPER);
|
||||
LOGO = confreader_getd(conf, "image", "logo", LOGO);
|
||||
|
||||
|
||||
|
||||
|
||||
confreader_free(conf);
|
||||
|
||||
TRACE("Loading complete");
|
||||
}
|
||||
|
||||
TRACE("Loading logo...");
|
||||
load_sprite_png(&logo, LOGO);
|
||||
TRACE("... done.");
|
||||
|
||||
/* Generate surface for background */
|
||||
sprite_t * bg_sprite;
|
||||
@ -280,16 +287,19 @@ int main (int argc, char ** argv) {
|
||||
win_height = height;
|
||||
|
||||
/* Do something with a window */
|
||||
TRACE("Connecting to window server...");
|
||||
yutani_window_t * wina = yutani_window_create(y, width, height);
|
||||
assert(wina);
|
||||
yutani_set_stack(y, wina, 0);
|
||||
ctx = init_graphics_yutani_double_buffer(wina);
|
||||
draw_fill(ctx, rgba(0,0,0,255));
|
||||
yutani_flip(y, wina);
|
||||
TRACE("... done.");
|
||||
|
||||
cairo_surface_t * cs = cairo_image_surface_create_for_data((void*)ctx->backbuffer, CAIRO_FORMAT_ARGB32, ctx->width, ctx->height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, ctx->width));
|
||||
cairo_t * cr = cairo_create(cs);
|
||||
|
||||
TRACE("Loading wallpaper...");
|
||||
{
|
||||
sprite_t * wallpaper = malloc(sizeof(sprite_t));
|
||||
load_sprite_png(wallpaper, WALLPAPER);
|
||||
@ -317,6 +327,7 @@ int main (int argc, char ** argv) {
|
||||
free(bg);
|
||||
free(wallpaper);
|
||||
}
|
||||
TRACE("... done.");
|
||||
|
||||
while (1) {
|
||||
|
||||
@ -331,13 +342,36 @@ int main (int argc, char ** argv) {
|
||||
char * foo = malloc(sizeof(uint32_t) * width * height);
|
||||
memcpy(foo, ctx->backbuffer, sizeof(uint32_t) * width * height);
|
||||
|
||||
for (int i = 0; i < LOGO_FINAL_OFFSET; i += 2) {
|
||||
memcpy(ctx->backbuffer, foo, sizeof(uint32_t) * width * height);
|
||||
draw_sprite(ctx, &logo, center_x(logo.width), center_y(logo.height) - i);
|
||||
flip(ctx);
|
||||
yutani_flip_region(y, wina, center_x(logo.width), center_y(logo.height) - i, logo.width, logo.height + 5);
|
||||
usleep(10000);
|
||||
TRACE("Begin animation.");
|
||||
{
|
||||
struct timeval start;
|
||||
gettimeofday(&start, NULL);
|
||||
|
||||
while (1) {
|
||||
uint32_t tick;
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
|
||||
uint32_t sec_diff = t.tv_sec - start.tv_sec;
|
||||
uint32_t usec_diff = t.tv_usec - start.tv_usec;
|
||||
|
||||
if (t.tv_usec < start.tv_usec) {
|
||||
sec_diff -= 1;
|
||||
usec_diff = (1000000 + t.tv_usec) - start.tv_usec;
|
||||
}
|
||||
|
||||
tick = (uint32_t)(sec_diff * 1000 + usec_diff / 1000);
|
||||
int i = (float)LOGO_FINAL_OFFSET * (float)tick / 700.0f;
|
||||
if (i >= LOGO_FINAL_OFFSET) break;
|
||||
|
||||
memcpy(ctx->backbuffer, foo, sizeof(uint32_t) * width * height);
|
||||
draw_sprite(ctx, &logo, center_x(logo.width), center_y(logo.height) - i);
|
||||
flip(ctx);
|
||||
yutani_flip_region(y, wina, center_x(logo.width), center_y(logo.height) - i, logo.width, logo.height + 5);
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
TRACE("End animation.");
|
||||
|
||||
size_t buf_size = wina->width * wina->height * sizeof(uint32_t);
|
||||
char * buf = malloc(buf_size);
|
||||
@ -447,6 +481,7 @@ int main (int argc, char ** argv) {
|
||||
struct yutani_msg_key_event kbd;
|
||||
struct yutani_msg_window_mouse_event mou;
|
||||
int msg_type = 0;
|
||||
collect_events:
|
||||
do {
|
||||
yutani_msg_t * msg = yutani_poll(y);
|
||||
switch (msg->type) {
|
||||
@ -533,8 +568,9 @@ int main (int argc, char ** argv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
goto collect_events;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,9 @@
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "lib/yutani.h"
|
||||
#include "lib/graphics.h"
|
||||
@ -159,15 +161,34 @@ static void set_focused(int i) {
|
||||
|
||||
void draw_sprite_scaled_alpha(gfx_context_t * ctx, sprite_t * sprite, int32_t x, int32_t y, uint16_t width, uint16_t height, float alpha);
|
||||
|
||||
#define ANIMATION_TICKS 50
|
||||
#define ANIMATION_TICKS 500
|
||||
#define SCALE_MAX 2.0f
|
||||
static void play_animation(int i) {
|
||||
|
||||
struct timeval start;
|
||||
gettimeofday(&start, NULL);
|
||||
|
||||
sprite_t * sprite = applications[i].icon_sprite;
|
||||
|
||||
int x = ICON_X;
|
||||
int y = ICON_TOP_Y + ICON_SPACING_Y * i;
|
||||
|
||||
for (int tick = 0; tick < ANIMATION_TICKS; tick++) {
|
||||
while (1) {
|
||||
uint32_t tick;
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
|
||||
uint32_t sec_diff = t.tv_sec - start.tv_sec;
|
||||
uint32_t usec_diff = t.tv_usec - start.tv_usec;
|
||||
|
||||
if (t.tv_usec < start.tv_usec) {
|
||||
sec_diff -= 1;
|
||||
usec_diff = (1000000 + t.tv_usec) - start.tv_usec;
|
||||
}
|
||||
|
||||
tick = (uint32_t)(sec_diff * 1000 + usec_diff / 1000);
|
||||
if (tick > ANIMATION_TICKS) break;
|
||||
|
||||
float percent = (float)tick / (float)ANIMATION_TICKS;
|
||||
float scale = 1.0f + (SCALE_MAX - 1.0f) * percent;
|
||||
float opacity = 1.0f - 1.0f * percent;
|
||||
|
Loading…
Reference in New Issue
Block a user