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:
parent
fd6ff8264c
commit
51fdb8bcaa
|
@ -527,3 +527,8 @@ static inline void wintype_arr_enable(bool arr[]) {
|
||||||
arr[i] = true;
|
arr[i] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current system clock in milliseconds.
|
||||||
|
*/
|
||||||
|
int64_t get_time_ms(void);
|
||||||
|
|
|
@ -497,6 +497,15 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
|
||||||
*opt = (struct options){
|
*opt = (struct options){
|
||||||
.backend = BKEND_XRENDER,
|
.backend = BKEND_XRENDER,
|
||||||
.glx_no_stencil = false,
|
.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_wmwin_focused = false,
|
||||||
.mark_ovredir_focused = false,
|
.mark_ovredir_focused = false,
|
||||||
.detect_rounded_corners = false,
|
.detect_rounded_corners = false,
|
||||||
|
|
18
src/config.h
18
src/config.h
|
@ -87,6 +87,24 @@ typedef struct options {
|
||||||
bool glx_no_stencil;
|
bool glx_no_stencil;
|
||||||
/// Whether to avoid rebinding pixmap on window damage.
|
/// Whether to avoid rebinding pixmap on window damage.
|
||||||
bool glx_no_rebind_pixmap;
|
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.
|
/// Custom fragment shader for painting windows, as a string.
|
||||||
char *glx_fshader_win_str;
|
char *glx_fshader_win_str;
|
||||||
/// Whether to detect rounded corners.
|
/// Whether to detect rounded corners.
|
||||||
|
|
|
@ -353,6 +353,29 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||||
// -O (fade_out_step)
|
// -O (fade_out_step)
|
||||||
if (config_lookup_float(&cfg, "fade-out-step", &dval))
|
if (config_lookup_float(&cfg, "fade-out-step", &dval))
|
||||||
opt->fade_out_step = normalize_d(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)
|
// -r (shadow_radius)
|
||||||
config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius);
|
config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius);
|
||||||
// -o (shadow_opacity)
|
// -o (shadow_opacity)
|
||||||
|
|
103
src/event.c
103
src/event.c
|
@ -202,6 +202,106 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
||||||
|
|
||||||
auto mw = (struct managed_win *)w;
|
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 ||
|
if (mw->state == WSTATE_UNMAPPED || mw->state == WSTATE_UNMAPPING ||
|
||||||
mw->state == WSTATE_DESTROYING) {
|
mw->state == WSTATE_DESTROYING) {
|
||||||
// Only restack the window to make sure we can handle future restack
|
// 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;
|
factor_change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mw->g.x = ce->x;
|
|
||||||
mw->g.y = ce->y;
|
|
||||||
|
|
||||||
if (mw->g.width != ce->width || mw->g.height != ce->height ||
|
if (mw->g.width != ce->width || mw->g.height != ce->height ||
|
||||||
mw->g.border_width != ce->border_width) {
|
mw->g.border_width != ce->border_width) {
|
||||||
log_trace("Window size changed, %dx%d -> %dx%d", mw->g.width,
|
log_trace("Window size changed, %dx%d -> %dx%d", mw->g.width,
|
||||||
|
|
53
src/picom.c
53
src/picom.c
|
@ -126,7 +126,7 @@ static inline void free_xinerama_info(session_t *ps) {
|
||||||
/**
|
/**
|
||||||
* Get current system clock in milliseconds.
|
* Get current system clock in milliseconds.
|
||||||
*/
|
*/
|
||||||
static inline int64_t get_time_ms(void) {
|
int64_t get_time_ms(void) {
|
||||||
struct timespec tp;
|
struct timespec tp;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &tp);
|
clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||||
return (int64_t)tp.tv_sec * 1000 + (int64_t)tp.tv_nsec / 1000000;
|
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.
|
// Opacity will not change, from now on.
|
||||||
rc_region_t *last_reg_ignore = rc_region_new();
|
rc_region_t *last_reg_ignore = rc_region_new();
|
||||||
|
|
||||||
|
|
|
@ -529,8 +529,10 @@ static void paint_root(session_t *ps, const region_t *reg_paint) {
|
||||||
* Generate shadow <code>Picture</code> for a window.
|
* Generate shadow <code>Picture</code> for a window.
|
||||||
*/
|
*/
|
||||||
static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacity) {
|
static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacity) {
|
||||||
const int width = w->widthb;
|
/* const int width = w->widthb; */
|
||||||
const int height = w->heightb;
|
/* 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);
|
// log_trace("(): building shadow for %s %d %d", w->name, width, height);
|
||||||
|
|
||||||
xcb_image_t *shadow_image = NULL;
|
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(®_tmp, ®_tmp, &bshape);
|
pixman_region32_intersect(®_tmp, ®_tmp, &bshape);
|
||||||
pixman_region32_fini(&bshape);
|
pixman_region32_fini(&bshape);
|
||||||
|
|
||||||
if (pixman_region32_not_empty(®_tmp)) {
|
reg_tmp = region;
|
||||||
|
if (pixman_region32_not_empty(®_tmp) || true) {
|
||||||
set_tgt_clip(ps, ®_tmp);
|
set_tgt_clip(ps, ®_tmp);
|
||||||
// Blur window background
|
// Blur window background
|
||||||
if (w->blur_background &&
|
if (w->blur_background &&
|
||||||
|
|
14
src/win.c
14
src/win.c
|
@ -1190,6 +1190,12 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
||||||
.dim = false,
|
.dim = false,
|
||||||
.invert_color = false,
|
.invert_color = false,
|
||||||
.blur_background = false,
|
.blur_background = false,
|
||||||
|
|
||||||
|
.oldX = -10000,
|
||||||
|
.oldY = -10000,
|
||||||
|
.oldW = 0,
|
||||||
|
.oldH = 0,
|
||||||
|
|
||||||
.reg_ignore = NULL,
|
.reg_ignore = NULL,
|
||||||
// The following ones are updated for other reasons
|
// The following ones are updated for other reasons
|
||||||
.pixmap_damaged = false, // updated by damage events
|
.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) {
|
static void map_win_finish(struct managed_win *w) {
|
||||||
w->in_openclose = false;
|
w->in_openclose = false;
|
||||||
|
w->isOld = true;
|
||||||
w->state = WSTATE_MAPPED;
|
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?
|
// XXX Can we assume map_state is always viewable?
|
||||||
w->a.map_state = XCB_MAP_STATE_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);
|
win_update_screen(ps, w);
|
||||||
|
|
||||||
// Set window event mask before reading properties so that no property
|
// Set window event mask before reading properties so that no property
|
||||||
|
|
|
@ -248,6 +248,13 @@ struct managed_win {
|
||||||
/// Whether to blur window background.
|
/// Whether to blur window background.
|
||||||
bool blur_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
|
#ifdef CONFIG_OPENGL
|
||||||
/// Textures and FBO background blur use.
|
/// Textures and FBO background blur use.
|
||||||
glx_blur_cache_t glx_blur_cache;
|
glx_blur_cache_t glx_blur_cache;
|
||||||
|
|
Loading…
Reference in New Issue