Skip to content

Commit

Permalink
Add unmap and workspace switch animation
Browse files Browse the repository at this point in the history
This will add unmap animation for windows that are hidden (e.g. minimized) and also a custom animation when switching workspace. Also we have two new animations, slide-in and slide-out that are automatically used for workspace switching.

Also with this changes opacity isn't added to the win_image itself but to the whole window so even shadow gets animated when animating windows. 

IMPORTANT: 
* For unmap animation fading needs to be turned on in the picom.conf as otherwise opacity is automatically set to 0 and so even if it animates you don't see it as the window is already transparent.
* For workspace switch animations window manager must set _NET_CURRENT_DESKTOP before doing the hide/show of windows for e.g. here is the change for Fluxbox:
pijulius/fluxbox@83ee4db

New options in settings are:
--animation-for-unmap-window
  Which animation to run when hiding (e.g. minimize) a window.
  Must be one of `auto`, `none`, `fly-in`, `zoom`,
  `slide-down`, `slide-up`, `slide-left`, `slide-right`
  `slide-in`, `slide-out`
  (default: auto).

--animation-for-workspace-switch-in
  Which animation to run on switching workspace for windows
  comming into view.
  IMPORTANT: window manager must set _NET_CURRENT_DESKTOP
  before doing the hide/show of windows
  Must be one of `auto`, `none`, `fly-in`, `zoom`,
  `slide-down`, `slide-up`, `slide-left`, `slide-right`
  `slide-in`, `slide-out`
  (default: auto).

--animation-for-workspace-switch-out
  Which animation to run on switching workspace for windows
  going out of view.
  IMPORTANT: window manager must set _NET_CURRENT_DESKTOP
  before doing the hide/show of windows
  Must be one of `auto`, `none`, `fly-in`, `zoom`,
  `slide-down`, `slide-up`, `slide-left`, `slide-right`
  `slide-in`, `slide-out`
  (default: auto).

also custom animations can be defined for both open and unmap with window types like this:
wintypes:
{
  notification = { animation = "slide-left"; animation-unmap = "zoom"; }
};
  • Loading branch information
pijulius committed Oct 17, 2021
1 parent 58c9c11 commit b92d410
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 8 deletions.
3 changes: 2 additions & 1 deletion src/atom.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
WM_CLIENT_MACHINE, \
_NET_ACTIVE_WINDOW, \
_COMPTON_SHADOW, \
_NET_WM_WINDOW_TYPE
_NET_WM_WINDOW_TYPE, \
_NET_CURRENT_DESKTOP

#define ATOM_LIST2 \
_NET_WM_WINDOW_TYPE_DESKTOP, \
Expand Down
4 changes: 4 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ typedef struct session {
int root_height;
/// Width of root window.
int root_width;
/// Current desktop number of root window
int root_desktop_num;
/// Desktop switch direction
int root_desktop_switch_direction;
// Damage of root window.
// Damage root_damage;
/// X Composite overlay window. Used if <code>--paint-on-overlay</code>.
Expand Down
17 changes: 17 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,18 @@ void set_default_winopts(options_t *opt, win_option_mask_t *mask, bool shadow_en
mask[i].animation = OPEN_WINDOW_ANIMATION_INVALID;
opt->wintype_option[i].animation = OPEN_WINDOW_ANIMATION_INVALID;
}
if (!mask[i].animation_unmap) {
mask[i].animation_unmap = OPEN_WINDOW_ANIMATION_INVALID;
opt->wintype_option[i].animation_unmap = OPEN_WINDOW_ANIMATION_INVALID;
}
if (!mask[i].animation_workspace_in) {
mask[i].animation_workspace_in = OPEN_WINDOW_ANIMATION_INVALID;
opt->wintype_option[i].animation_workspace_in = OPEN_WINDOW_ANIMATION_INVALID;
}
if (!mask[i].animation_workspace_out) {
mask[i].animation_workspace_out = OPEN_WINDOW_ANIMATION_INVALID;
opt->wintype_option[i].animation_workspace_out = OPEN_WINDOW_ANIMATION_INVALID;
}
if (!mask[i].clip_shadow_above) {
mask[i].clip_shadow_above = true;
opt->wintype_option[i].clip_shadow_above = false;
Expand All @@ -514,6 +526,8 @@ void set_default_winopts(options_t *opt, win_option_mask_t *mask, bool shadow_en
enum open_window_animation parse_open_window_animation(const char *src) {
if (strcmp(src, "none") == 0) {
return OPEN_WINDOW_ANIMATION_NONE;
}else if (strcmp(src, "auto") == 0) {
return OPEN_WINDOW_ANIMATION_AUTO;
} else if (strcmp(src, "fly-in") == 0) {
return OPEN_WINDOW_ANIMATION_FLYIN;
} else if (strcmp(src, "zoom") == 0) {
Expand Down Expand Up @@ -578,6 +592,9 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
.animations = false,
.animation_for_open_window = OPEN_WINDOW_ANIMATION_NONE,
.animation_for_transient_window = OPEN_WINDOW_ANIMATION_NONE,
.animation_for_unmap_window = OPEN_WINDOW_ANIMATION_AUTO,
.animation_for_workspace_switch_in = OPEN_WINDOW_ANIMATION_AUTO,
.animation_for_workspace_switch_out = OPEN_WINDOW_ANIMATION_AUTO,
.animation_stiffness = 200.0,
.animation_window_mass = 1.0,
.animation_dampening = 25,
Expand Down
16 changes: 16 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,15 @@ enum backend {

enum open_window_animation {
OPEN_WINDOW_ANIMATION_NONE = 0,
OPEN_WINDOW_ANIMATION_AUTO,
OPEN_WINDOW_ANIMATION_FLYIN,
OPEN_WINDOW_ANIMATION_ZOOM,
OPEN_WINDOW_ANIMATION_SLIDE_UP,
OPEN_WINDOW_ANIMATION_SLIDE_DOWN,
OPEN_WINDOW_ANIMATION_SLIDE_LEFT,
OPEN_WINDOW_ANIMATION_SLIDE_RIGHT,
OPEN_WINDOW_ANIMATION_SLIDE_IN,
OPEN_WINDOW_ANIMATION_SLIDE_OUT,
OPEN_WINDOW_ANIMATION_INVALID,
};

Expand All @@ -58,6 +61,9 @@ typedef struct win_option_mask {
bool opacity : 1;
bool clip_shadow_above : 1;
enum open_window_animation animation;
enum open_window_animation animation_unmap;
enum open_window_animation animation_workspace_in;
enum open_window_animation animation_workspace_out;
} win_option_mask_t;

typedef struct win_option {
Expand All @@ -70,6 +76,9 @@ typedef struct win_option {
double opacity;
bool clip_shadow_above;
enum open_window_animation animation;
enum open_window_animation animation_unmap;
enum open_window_animation animation_workspace_in;
enum open_window_animation animation_workspace_out;
} win_option_t;

enum blur_method {
Expand Down Expand Up @@ -193,6 +202,13 @@ typedef struct options {
enum open_window_animation animation_for_open_window;
/// Which animation to run when opening a transient window
enum open_window_animation animation_for_transient_window;
/// Which animation to run when unmapping (e.g. minimizing) a window
enum open_window_animation animation_for_unmap_window;
/// Which animation to run when switching workspace
/// IMPORTANT: will only work if window manager updates
/// _NET_CURRENT_DESKTOP before doing the hide/show of windows
enum open_window_animation animation_for_workspace_switch_in;
enum open_window_animation animation_for_workspace_switch_out;
/// Spring stiffness for animation
double animation_stiffness;
/// Window mass for animation
Expand Down
53 changes: 52 additions & 1 deletion src/config_libconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,30 @@ static inline void parse_wintype_config(const config_t *cfg, const char *member_
o->animation = animation;
mask->animation = OPEN_WINDOW_ANIMATION_INVALID;
}
if (config_setting_lookup_string(setting, "animation-unmap", &sval)) {
enum open_window_animation animation = parse_open_window_animation(sval);
if (animation >= OPEN_WINDOW_ANIMATION_INVALID)
animation = OPEN_WINDOW_ANIMATION_NONE;

o->animation_unmap = animation;
mask->animation_unmap = OPEN_WINDOW_ANIMATION_INVALID;
}
if (config_setting_lookup_string(setting, "animation-workspace-in", &sval)) {
enum open_window_animation animation = parse_open_window_animation(sval);
if (animation >= OPEN_WINDOW_ANIMATION_INVALID)
animation = OPEN_WINDOW_ANIMATION_NONE;

o->animation_workspace_in = animation;
mask->animation_workspace_in = OPEN_WINDOW_ANIMATION_INVALID;
}
if (config_setting_lookup_string(setting, "animation-workspace-out", &sval)) {
enum open_window_animation animation = parse_open_window_animation(sval);
if (animation >= OPEN_WINDOW_ANIMATION_INVALID)
animation = OPEN_WINDOW_ANIMATION_NONE;

o->animation_workspace_out = animation;
mask->animation_workspace_out = OPEN_WINDOW_ANIMATION_INVALID;
}

double fval;
if (config_setting_lookup_float(setting, "opacity", &fval)) {
Expand Down Expand Up @@ -546,11 +570,38 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
if (config_lookup_string(&cfg, "animation-for-transient-window", &sval)) {
enum open_window_animation animation = parse_open_window_animation(sval);
if (animation >= OPEN_WINDOW_ANIMATION_INVALID) {
log_fatal("Invalid open-window animation %s", sval);
log_fatal("Invalid transient-window animation %s", sval);
goto err;
}
opt->animation_for_transient_window = animation;
}
// --animation-for-unmap-window
if (config_lookup_string(&cfg, "animation-for-unmap-window", &sval)) {
enum open_window_animation animation = parse_open_window_animation(sval);
if (animation >= OPEN_WINDOW_ANIMATION_INVALID) {
log_fatal("Invalid unmap-window animation %s", sval);
goto err;
}
opt->animation_for_unmap_window = animation;
}
// --animation-for-workspace-switch-in
if (config_lookup_string(&cfg, "animation-for-workspace-switch-in", &sval)) {
enum open_window_animation animation = parse_open_window_animation(sval);
if (animation >= OPEN_WINDOW_ANIMATION_INVALID) {
log_fatal("Invalid workspace-switch-in animation %s", sval);
goto err;
}
opt->animation_for_workspace_switch_in = animation;
}
// --animation-for-workspace-switch-out
if (config_lookup_string(&cfg, "animation-for-workspace-switch-out", &sval)) {
enum open_window_animation animation = parse_open_window_animation(sval);
if (animation >= OPEN_WINDOW_ANIMATION_INVALID) {
log_fatal("Invalid workspace-switch-out animation %s", sval);
goto err;
}
opt->animation_for_workspace_switch_out = animation;
}
// --animation-stiffness
config_lookup_float(&cfg, "animation-stiffness", &opt->animation_stiffness);
// --animation-window-mass
Expand Down
11 changes: 11 additions & 0 deletions src/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,17 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
}

if (ps->root == ev->window) {
// If desktop number property changes
if (ev->atom == ps->atoms->a_NET_CURRENT_DESKTOP) {
auto prop = x_get_prop(ps->c, ps->root, ps->atoms->a_NET_CURRENT_DESKTOP,
1L, XCB_ATOM_CARDINAL, 32);

if (prop.nitems) {
ps->root_desktop_switch_direction = ((int)*prop.c32) - ps->root_desktop_num;
ps->root_desktop_num = (int)*prop.c32;
}
}

if (ps->o.use_ewmh_active_win && ps->atoms->a_NET_ACTIVE_WINDOW == ev->atom) {
// to update focus
ps->pending_updates = true;
Expand Down
27 changes: 27 additions & 0 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,33 @@ static void usage(const char *argv0, int ret) {
" `slide-down`, `slide-up`, `slide-left`, `slide-right`\n"
" (default: none).\n"
"\n"
"--animation-for-unmap-window\n"
" Which animation to run when hiding (e.g. minimize) a window.\n"
" Must be one of `auto`, `none`, `fly-in`, `zoom`,\n"
" `slide-down`, `slide-up`, `slide-left`, `slide-right`\n"
" `slide-in`, `slide-out`\n"
" (default: auto).\n"
"\n"
"--animation-for-workspace-switch-in\n"
" Which animation to run on switching workspace for windows\n"
" comming into view.\n"
" IMPORTANT: window manager must set _NET_CURRENT_DESKTOP\n"
" before doing the hide/show of windows\n"
" Must be one of `auto`, `none`, `fly-in`, `zoom`,\n"
" `slide-down`, `slide-up`, `slide-left`, `slide-right`\n"
" `slide-in`, `slide-out`\n"
" (default: auto).\n"
"\n"
"--animation-for-workspace-switch-out\n"
" Which animation to run on switching workspace for windows\n"
" going out of view.\n"
" IMPORTANT: window manager must set _NET_CURRENT_DESKTOP\n"
" before doing the hide/show of windows\n"
" Must be one of `auto`, `none`, `fly-in`, `zoom`,\n"
" `slide-down`, `slide-up`, `slide-left`, `slide-right`\n"
" `slide-in`, `slide-out`\n"
" (default: auto).\n"
"\n"
"--animation-stiffness\n"
" Stiffness (a.k.a. tension) parameter for animation (default: 200.0).\n"
"\n"
Expand Down
33 changes: 32 additions & 1 deletion src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,14 @@ static void configure_root(session_t *ps) {
ps->root_width = r->width;
ps->root_height = r->height;

auto prop = x_get_prop(ps->c, ps->root, ps->atoms->a_NET_CURRENT_DESKTOP,
1L, XCB_ATOM_CARDINAL, 32);

ps->root_desktop_switch_direction = 0;
if (prop.nitems) {
ps->root_desktop_num = (int)*prop.c32;
}

rebuild_screen_reg(ps);
rebuild_shadow_exclude_reg(ps);

Expand Down Expand Up @@ -654,6 +662,7 @@ paint_preprocess(session_t *ps, bool *fade_running, bool *animation_running) {
ps->animation_time = now;

double delta_secs = (double)(now - ps->animation_time) / 1000;
if (!delta_secs || delta_secs > 0.01) delta_secs = 0.01;

// First, let's process fading
win_stack_foreach_managed_safe(w, &ps->window_stack) {
Expand All @@ -663,7 +672,7 @@ paint_preprocess(session_t *ps, bool *fade_running, bool *animation_running) {

// IMPORTANT: These window animation steps must happen before any other
// [pre]processing. This is because it changes the window's geometry.
if (ps->o.animations &&
if (ps->o.animations &&
!isnan(w->animation_progress) && w->animation_progress != 1.0 &&
ps->o.wintype_option[w->window_type].animation != 0 &&
win_is_mapped_in_x(w))
Expand Down Expand Up @@ -804,6 +813,27 @@ paint_preprocess(session_t *ps, bool *fade_running, bool *animation_running) {
w->animation_velocity_h = 0.0;
}

if (!ps->root_desktop_switch_direction) {
if (w->state == WSTATE_UNMAPPING) {
steps = 0;
double new_opacity = clamp(
w->opacity_target_old-w->animation_progress,
w->opacity_target, 1);

if (new_opacity < w->opacity)
w->opacity = new_opacity;

} else if (w->state == WSTATE_MAPPING) {
steps = 0;
double new_opacity = clamp(
w->animation_progress,
0.0, w->opacity_target);

if (new_opacity > w->opacity)
w->opacity = new_opacity;
}
}

*animation_running = true;
}

Expand Down Expand Up @@ -1729,6 +1759,7 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) {
}
if (!animation_running) {
ps->animation_time = 0L;
ps->root_desktop_switch_direction = 0;
}

// TODO(yshui) Investigate how big the X critical section needs to be. There are
Expand Down

2 comments on commit b92d410

@Vermoot
Copy link

@Vermoot Vermoot commented on b92d410 Nov 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! I'd usually leave this in an issue, but they're not enabled on this repo so I'll just leave a comment on the commit that seems the most relevant.

When animation-for-open-window is set to none, some windows are still drawn when I'm changing workspaces. I can't do anything on them, they're not actually there, but they're still drawn.

I do think this is only on your fork. I'd be happy to provide more info or do some testing if neede.

@Vermoot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To add to that, using zoom for animation-for-open-window makes it so windows leave a weird artifact when changing workspace
2021-11-11-005354_1039x489_scrot

Please sign in to comment.