Implement animations

Squashed all the stuff:

init

Update README.md

options

performance

Animation no longer jumps if started in the middle of an animation

Doubled default transition length

Minor bugfix, preformance

Track x and y separately to aviod jumping in mid-animation repositioning

Added video to readme

docs

docs

fixed graphical glitch with non-transparent windows

now animates window scaling too (but only if the window grows)

added options for size transitions

and actually respect the new options..

and actually respect the new options..

added center-spawn option

added center-spawn-screen option

fixed center spawn

added no-scale-down

goofed

remember old windows

remember old windows

docs

fixed shadow

fixed shadow

fixed shadow

fixed shadow

lost no-scale-down due to revert

lost spawn-center due to revert

Fixed #2

fix missing window borders
This commit is contained in:
blackcapcoder 2017-10-07 15:22:37 +02:00 committed by Martin T. H. Sandsmark
parent fd6ff8264c
commit 51fdb8bcaa
9 changed files with 234 additions and 7 deletions

View File

@ -527,3 +527,8 @@ static inline void wintype_arr_enable(bool arr[]) {
arr[i] = true;
}
}
/**
* Get current system clock in milliseconds.
*/
int64_t get_time_ms(void);

View File

@ -497,6 +497,15 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
*opt = (struct options){
.backend = BKEND_XRENDER,
.glx_no_stencil = false,
.transition_length = 300,
.transition_pow_x = 1.5,
.transition_pow_y = 1.5,
.transition_pow_w = 1.5,
.transition_pow_h = 1.5,
.size_transition = true,
.no_scale_down = false,
.spawn_center_screen = false,
.spawn_center = true,
.mark_wmwin_focused = false,
.mark_ovredir_focused = false,
.detect_rounded_corners = false,

View File

@ -87,6 +87,24 @@ typedef struct options {
bool glx_no_stencil;
/// Whether to avoid rebinding pixmap on window damage.
bool glx_no_rebind_pixmap;
/// Length of window transitions
int transition_length;
/// For smoothing on the x-coordinate of window animations
float transition_pow_x;
/// For smoothing on the y-coordinate of window animations
float transition_pow_y;
/// For smoothing on the width of window animations
float transition_pow_w;
/// For smoothing on the height of window animations
float transition_pow_h;
/// Wether to animate on window size change
bool size_transition;
/// Wether to scale new windows in from the center of the screen
bool spawn_center_screen;
/// Wether to scale new windows in from their center
bool spawn_center;
/// Does not animate downscaling
bool no_scale_down;
/// Custom fragment shader for painting windows, as a string.
char *glx_fshader_win_str;
/// Whether to detect rounded corners.

View File

@ -353,6 +353,29 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
// -O (fade_out_step)
if (config_lookup_float(&cfg, "fade-out-step", &dval))
opt->fade_out_step = normalize_d(dval);
// --transition-length
if (config_lookup_int(&cfg, "transition-length", &ival))
opt->transition_length = ival;
// --transition-pow-x
if (config_lookup_float(&cfg, "transition-pow-x", &dval))
opt->transition_pow_x = dval;
// --transition-pow-y
if (config_lookup_float(&cfg, "transition-pow-y", &dval))
opt->transition_pow_y = dval;
// --transition-pow-w
if (config_lookup_float(&cfg, "transition-pow-w", &dval))
opt->transition_pow_w = dval;
// --transition-pow-h
if (config_lookup_float(&cfg, "transition-pow-h", &dval))
opt->transition_pow_h = dval;
// --size-transition
lcfg_lookup_bool(&cfg, "size-transition", &opt->size_transition);
// --spawn-center-screen
lcfg_lookup_bool(&cfg, "spawn-center-screen", &opt->spawn_center_screen);
// --spawn-center
lcfg_lookup_bool(&cfg, "spawn-center", &opt->spawn_center);
// --no-scale-down
lcfg_lookup_bool(&cfg, "no-scale-down", &opt->no_scale_down);
// -r (shadow_radius)
config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius);
// -o (shadow_opacity)

View File

@ -202,6 +202,106 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
auto mw = (struct managed_win *)w;
float t = get_time_ms();
if (mw->oldX == -10000 && mw->oldY == -10000 && mw->oldW == 0 && mw->oldH == 0) {
if (!mw->isOld) {
/* mw->isOld = true; */
if (ps->o.spawn_center_screen) {
mw->oldX = ps->root_width/2;
mw->oldY = ps->root_height/2;
mw->oldW = 1;
mw->oldH = 1;
} else if (ps->o.spawn_center) {
mw->oldX = ce->x + ce->width/2;
mw->oldY = ce->y + ce->height/2;
mw->oldW = 1;
mw->oldH = 1;
} else {
mw->oldX = ce->x;
mw->oldY = ce->y;
mw->oldW = ce->width;
mw->oldH = ce->height;
}
} else {
mw->oldX = ce->x;
mw->oldY = ce->y;
mw->oldW = ce->width;
mw->oldH = ce->height;
}
mw->newX = ce->x;
mw->newY = ce->y;
mw->newW = ce->width;
mw->newH = ce->height;
mw->moveTimeX = t;
mw->moveTimeY = t;
mw->moveTimeW = t;
mw->moveTimeH = t;
} else {
if (mw->newX == mw->g.x && mw->newY == mw->g.y) {
mw->oldX = mw->g.x;
mw->oldY = mw->g.y;
mw->oldW = mw->g.width;
mw->oldH = mw->g.height;
mw->moveTimeX = t;
mw->moveTimeY = t;
mw->moveTimeW = t;
mw->moveTimeH = t;
}
if (mw->newX != ce->x || mw->newY != ce->y || mw->newW != ce->width || mw->newH != ce->height) {
float moveDx = ((float) t - mw->moveTimeX) / ps->o.transition_length;
float moveDy = ((float) t - mw->moveTimeY) / ps->o.transition_length;
float moveDw = ((float) t - mw->moveTimeW) / ps->o.transition_length;
float moveDh = ((float) t - mw->moveTimeH) / ps->o.transition_length;
if (mw->moveTimeX != 0.0 && moveDx < 1.0 && mw->oldX != mw->newX) {
float oldMoveDx = pow((float) (mw->newX - mw->g.x) / (float) (mw->newX - ce->x), 1 / ps->o.transition_pow_x);
float fakeT = (t - oldMoveDx * (float) ps->o.transition_length);
/* printf("X: %f,%f\n", fakeT, t); */
mw->moveTimeX = isnanf(fakeT)? t : fakeT;
} else {
mw->moveTimeX = t;
}
if (mw->moveTimeY != 0.0 && moveDy < 1.0 && mw->oldY != mw->newY) {
float oldMoveDy = pow((float) (mw->newY - mw->g.y) / (float) (mw->newY - ce->y), 1 / ps->o.transition_pow_y);
float fakeT = (t - oldMoveDy * (float) ps->o.transition_length);
/* printf("Y: %f,%f\n", fakeT, t); */
mw->moveTimeY = isnanf(fakeT)? t : fakeT;
} else {
mw->moveTimeY = t;
}
if (mw->moveTimeW != 0.0 && moveDw < 1.0 && mw->oldW != mw->newW) {
float oldMoveDw = pow((float) (mw->newW - mw->g.width) / (float) (mw->newW - ce->width), 1 / ps->o.transition_pow_w);
float fakeT = (t - oldMoveDw * (float) ps->o.transition_length);
/* printf("Y: %f,%f\n", fakeT, t); */
mw->moveTimeW = isnanf(fakeT)? t : fakeT;
} else {
mw->moveTimeW = t;
}
if (mw->moveTimeH != 0.0 && moveDh < 1.0 && mw->oldH != mw->newH) {
float oldMoveDh = pow((float) (mw->newH - mw->g.height) / (float) (mw->newH - ce->height), 1 / ps->o.transition_pow_h);
float fakeT = (t - oldMoveDh * (float) ps->o.transition_length);
/* printf("Y: %f,%f\n", fakeT, t); */
mw->moveTimeH = isnanf(fakeT)? t : fakeT;
} else {
mw->moveTimeH = t;
}
mw->oldX = mw->newX;
mw->oldY = mw->newY;
mw->oldW = mw->newW;
mw->oldH = mw->newH;
mw->newX = ce->x;
mw->newY = ce->y;
mw->newW = ce->width;
mw->newH = ce->height;
if (ps->o.no_scale_down && mw->newW < mw->oldW) { mw->oldW = mw->newW; }
if (ps->o.no_scale_down && mw->newH < mw->oldH) { mw->oldH = mw->newH; }
}
}
if (mw->state == WSTATE_UNMAPPED || mw->state == WSTATE_UNMAPPING ||
mw->state == WSTATE_DESTROYING) {
// Only restack the window to make sure we can handle future restack
@ -218,9 +318,6 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
factor_change = true;
}
mw->g.x = ce->x;
mw->g.y = ce->y;
if (mw->g.width != ce->width || mw->g.height != ce->height ||
mw->g.border_width != ce->border_width) {
log_trace("Window size changed, %dx%d -> %dx%d", mw->g.width,

View File

@ -126,7 +126,7 @@ static inline void free_xinerama_info(session_t *ps) {
/**
* Get current system clock in milliseconds.
*/
static inline int64_t get_time_ms(void) {
int64_t get_time_ms(void) {
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
return (int64_t)tp.tv_sec * 1000 + (int64_t)tp.tv_nsec / 1000000;
@ -676,6 +676,57 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
}
}
win_stack_foreach_managed(w, &ps->window_stack) {
bool posChanged = (w->oldX != -10000 && w->oldY != -10000 && w->oldW != 0 && w->oldH != 0)
&& (w->g.x != w->newX || w->g.y != w->newY || w->g.width != w->newW || w->g.height != w->newH);
if (posChanged) {
float t = get_time_ms();
float moveDx = (t - w->moveTimeX) / ps->o.transition_length;
float moveDy = (t - w->moveTimeY) / ps->o.transition_length;
float moveDw = (t - w->moveTimeW) / ps->o.transition_length;
float moveDh = (t - w->moveTimeH) / ps->o.transition_length;
if (moveDx >= 1.0) moveDx = 1.0;
if (moveDy >= 1.0) moveDy = 1.0;
if (moveDw >= 1.0) moveDw = 1.0;
if (moveDh >= 1.0) moveDh = 1.0;
float q = pow (moveDx, ps->o.transition_pow_x);
float k = pow (moveDy, ps->o.transition_pow_y);
float g = pow (moveDw, ps->o.transition_pow_w);
float z = pow (moveDh, ps->o.transition_pow_h);
float x = (float) w->oldX * (1-q) + (float) w->newX * q;
float y = (float) w->oldY * (1-k) + (float) w->newY * k;
float W = (float) w->oldW * (1-g) + (float) w->newW * g;
float h = (float) w->oldH * (1-z) + (float) w->newH * z;
add_damage_from_win(ps, w);
w->g.x = (int) x;
w->g.y = (int) y;
if (ps->o.size_transition) {
w->g.width = (int) W;
w->g.height = (int) h;
}
/* w->to_paint = true; */
w->mode = WMODE_TRANS;
*fade_running = true;
}
// TODO
//if ((w->shadow && posChanged) || (ps->o.size_transition && w->pixmap_damaged)) {
// rc_region_unref(&w->extents);
// rc_region_unref(&w->border_size);
// w->extents = win_extents(ps, w);
// calc_win_size(ps, w);
// if (ps->shape_exists && ps->o.shadow_ignore_shaped
// && ps->o.detect_rounded_corners && w->bounding_shaped)
// win_update_shape(ps, w);
//}
/* add_damage_win(ps, w); */
}
// Opacity will not change, from now on.
rc_region_t *last_reg_ignore = rc_region_new();

View File

@ -529,8 +529,10 @@ static void paint_root(session_t *ps, const region_t *reg_paint) {
* Generate shadow <code>Picture</code> for a window.
*/
static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacity) {
const int width = w->widthb;
const int height = w->heightb;
/* const int width = w->widthb; */
/* const int height = w->heightb; */
const int width = w->newW; // TODO!
const int height = w->newH;
// log_trace("(): building shadow for %s %d %d", w->name, width, height);
xcb_image_t *shadow_image = NULL;
@ -909,7 +911,8 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
pixman_region32_intersect(&reg_tmp, &reg_tmp, &bshape);
pixman_region32_fini(&bshape);
if (pixman_region32_not_empty(&reg_tmp)) {
reg_tmp = region;
if (pixman_region32_not_empty(&reg_tmp) || true) {
set_tgt_clip(ps, &reg_tmp);
// Blur window background
if (w->blur_background &&

View File

@ -1190,6 +1190,12 @@ struct win *fill_win(session_t *ps, struct win *w) {
.dim = false,
.invert_color = false,
.blur_background = false,
.oldX = -10000,
.oldY = -10000,
.oldW = 0,
.oldH = 0,
.reg_ignore = NULL,
// The following ones are updated for other reasons
.pixmap_damaged = false, // updated by damage events
@ -1772,6 +1778,7 @@ static void destroy_win_finish(session_t *ps, struct win *w) {
static void map_win_finish(struct managed_win *w) {
w->in_openclose = false;
w->isOld = true;
w->state = WSTATE_MAPPED;
}
@ -2080,6 +2087,13 @@ void map_win_start(session_t *ps, struct managed_win *w) {
// XXX Can we assume map_state is always viewable?
w->a.map_state = XCB_MAP_STATE_VIEWABLE;
if (!w->isOld) {
w->oldX = -10000;
w->oldY = -10000;
w->oldW = 0;
w->oldH = 0;
}
win_update_screen(ps, w);
// Set window event mask before reading properties so that no property

View File

@ -248,6 +248,13 @@ struct managed_win {
/// Whether to blur window background.
bool blur_background;
/// Animation state
int oldX; int oldY; int oldW; int oldH;
int newX; int newY; int newW; int newH;
float moveTimeX; float moveTimeY;
float moveTimeW; float moveTimeH;
bool isOld;
#ifdef CONFIG_OPENGL
/// Textures and FBO background blur use.
glx_blur_cache_t glx_blur_cache;