Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animatation part I: fading is animation #1220

Merged
merged 6 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 11 additions & 34 deletions src/backend/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "config.h"
#include "log.h"
#include "region.h"
#include "transition.h"
#include "types.h"
#include "win.h"
#include "x.h"
Expand Down Expand Up @@ -253,45 +254,20 @@
auto real_win_mode = w->mode;
coord_t window_coord = {.x = w->g.x, .y = w->g.y};

const double window_opacity = animatable_get(&w->opacity);
if (w->blur_background &&
(ps->o.force_win_blend || real_win_mode == WMODE_TRANS ||
(ps->o.blur_background_frame && real_win_mode == WMODE_FRAME_TRANS))) {
// Minimize the region we try to blur, if the window
// itself is not opaque, only the frame is.

double blur_opacity = 1;
if (w->opacity < (1.0 / MAX_ALPHA)) {
// Hide blur for fully transparent windows.
blur_opacity = 0;
} else if (w->state == WSTATE_MAPPING) {
// Gradually increase the blur intensity during
// fading in.
assert(w->opacity <= w->opacity_target);
blur_opacity = w->opacity / w->opacity_target;
} else if (w->state == WSTATE_UNMAPPING ||
w->state == WSTATE_DESTROYING) {
// Gradually decrease the blur intensity during
// fading out.
assert(w->opacity <= w->opacity_target_old);
blur_opacity = w->opacity / w->opacity_target_old;
} else if (w->state == WSTATE_FADING) {
if (w->opacity < w->opacity_target &&
w->opacity_target_old < (1.0 / MAX_ALPHA)) {
// Gradually increase the blur intensity during
// fading in.
assert(w->opacity <= w->opacity_target);
blur_opacity = w->opacity / w->opacity_target;
} else if (w->opacity > w->opacity_target &&
w->opacity_target < (1.0 / MAX_ALPHA)) {
// Gradually decrease the blur intensity during
// fading out.
assert(w->opacity <= w->opacity_target_old);
blur_opacity = w->opacity / w->opacity_target_old;
}
}
const double blur_opacity = animatable_get(&w->blur_opacity);
assert(blur_opacity >= 0 && blur_opacity <= 1);

if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
if (blur_opacity * MAX_ALPHA < 1) {
// We don't need to blur if it would be completely
// transparent
} else if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
// We need to blur the bounding shape of the window
// (reg_paint_in_bound = reg_bound \cap reg_paint)
ps->backend_data->ops->blur(
Expand Down Expand Up @@ -404,7 +380,7 @@
if (w->dim) {
dim_opacity = ps->o.inactive_dim;
if (!ps->o.inactive_dim_fixed) {
dim_opacity *= w->opacity;
dim_opacity *= window_opacity;

Check warning on line 383 in src/backend/backend.c

View check run for this annotation

Codecov / codecov/patch

src/backend/backend.c#L383

Added line #L383 was not covered by tests
}
}

Expand All @@ -418,7 +394,8 @@
ps->backend_data, IMAGE_PROPERTY_DIM_LEVEL, w->win_image,
&dim_opacity);
ps->backend_data->ops->set_image_property(
ps->backend_data, IMAGE_PROPERTY_OPACITY, w->win_image, &w->opacity);
ps->backend_data, IMAGE_PROPERTY_OPACITY, w->win_image,
&window_opacity);
ps->backend_data->ops->set_image_property(
ps->backend_data, IMAGE_PROPERTY_CORNER_RADIUS, w->win_image,
(double[]){w->corner_radius});
Expand All @@ -440,7 +417,7 @@
w->fg_shader ? (void *)w->fg_shader->backend_shader : NULL);
}

if (w->opacity * MAX_ALPHA < 1) {
if (window_opacity * MAX_ALPHA < 1) {
// We don't need to paint the window body itself if it's
// completely transparent.
goto skip;
Expand Down
11 changes: 8 additions & 3 deletions src/dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
#include "list.h"
#include "log.h"
#include "string_utils.h"
#include "transition.h"
#include "types.h"
#include "uthash_extra.h"
#include "utils.h"
#include "win.h"
#include "win_defs.h"

#include "dbus.h"

Expand Down Expand Up @@ -876,7 +878,7 @@

if (!strcmp("Mapped", target)) {
cdbus_reply(ps, msg, cdbus_append_bool_variant,
(bool[]){win_is_mapped_in_x(w)});
(bool[]){w->state == WSTATE_MAPPED});

Check warning on line 881 in src/dbus.c

View check run for this annotation

Codecov / codecov/patch

src/dbus.c#L881

Added line #L881 was not covered by tests
return true;
}

Expand Down Expand Up @@ -991,14 +993,17 @@
cdbus_m_win_get_do(class_general, cdbus_reply_string);
cdbus_m_win_get_do(role, cdbus_reply_string);

cdbus_m_win_get_do(opacity, cdbus_reply_double);
cdbus_m_win_get_do(opacity_target, cdbus_reply_double);
cdbus_m_win_get_do(opacity.target, cdbus_reply_double);

Check warning on line 996 in src/dbus.c

View check run for this annotation

Codecov / codecov/patch

src/dbus.c#L996

Added line #L996 was not covered by tests
cdbus_m_win_get_do(has_opacity_prop, cdbus_reply_bool);
cdbus_m_win_get_do(opacity_prop, cdbus_reply_uint32);
cdbus_m_win_get_do(opacity_is_set, cdbus_reply_bool);
cdbus_m_win_get_do(opacity_set, cdbus_reply_double);

cdbus_m_win_get_do(frame_opacity, cdbus_reply_double);
if (strcmp(target, "opacity") == 0) {
cdbus_reply_double(ps, msg, animatable_get(&w->opacity));
return true;

Check warning on line 1005 in src/dbus.c

View check run for this annotation

Codecov / codecov/patch

src/dbus.c#L1003-L1005

Added lines #L1003 - L1005 were not covered by tests
}
if (!strcmp("left_width", target)) {
cdbus_reply_int32(ps, msg, w->frame_extents.left);
return true;
Expand Down
62 changes: 40 additions & 22 deletions src/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "region.h"
#include "utils.h"
#include "win.h"
#include "win_defs.h"
#include "x.h"

/// Event handling with X is complicated. Handling events with other events possibly
Expand Down Expand Up @@ -273,18 +274,27 @@
assert(&mw->base == w);
mw = NULL;
}

// A window can't be a client window and a top-level window at the same time,
// so only one of `w` and `mw` can be non-NULL
assert(w == NULL || mw == NULL);

if (w != NULL) {
auto _ attr_unused = destroy_win_start(ps, w);
} else if (mw != NULL) {
destroy_win_start(ps, w);
if (!w->managed || !((struct managed_win *)w)->to_paint) {
// If the window wasn't managed, or was already not rendered,
// we don't need to fade it out.
destroy_win_finish(ps, w);
}
return;
}
if (mw != NULL) {
win_unmark_client(ps, mw);
win_set_flags(mw, WIN_FLAGS_CLIENT_STALE);
ps->pending_updates = true;
} else {
log_debug("Received a destroy notify from an unknown window, %#010x",
ev->window);
return;
}
log_debug("Received a destroy notify from an unknown window, %#010x", ev->window);
}

static inline void ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) {
Expand All @@ -308,6 +318,13 @@
}

win_set_flags(w, WIN_FLAGS_MAPPED);
// We set `ever_damaged` to false here, instead of in `map_win_start`,
// because we might receive damage events before that function is called
// (which is called when we handle the `WIN_FLAGS_MAPPED` flag), in
// which case `repair_win` will be called, which uses `ever_damaged` so
// it needs to be correct. This also covers the case where the window is
// unmapped before `map_win_start` is called.
w->ever_damaged = false;

// FocusIn/Out may be ignored when the window is unmapped, so we must
// recheck focus here
Expand Down Expand Up @@ -349,8 +366,7 @@
{
auto w = find_win(ps, ev->window);
if (w) {
auto ret = destroy_win_start(ps, w);
if (!ret && w->managed) {
if (w->managed) {
auto mw = (struct managed_win *)w;
// Usually, damage for unmapped windows
// are added in `paint_preprocess`, when
Expand All @@ -362,8 +378,17 @@
if (mw->to_paint) {
add_damage_from_win(ps, mw);
}
CHECK(win_skip_fading(ps, mw));
// Emulating what X server does: a destroyed
// window is always unmapped first.
if (mw->state == WSTATE_MAPPED) {
unmap_win_start(ps, mw);

Check warning on line 384 in src/event.c

View check run for this annotation

Codecov / codecov/patch

src/event.c#L384

Added line #L384 was not covered by tests
}
}
// Window reparenting is unlike normal window destruction,
// This window is going to be rendered under another
// parent, so we don't fade here.
destroy_win_start(ps, w);
destroy_win_finish(ps, w);
}
}

Expand All @@ -378,25 +403,14 @@
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
} else {
auto w_real_top = find_managed_window_or_parent(ps, ev->parent);
if (w_real_top && w_real_top->state != WSTATE_UNMAPPED &&
w_real_top->state != WSTATE_UNMAPPING) {
if (w_real_top) {
log_debug("Mark window %#010x (%s) as having a stale "
"client",
w_real_top->base.id, w_real_top->name);
win_set_flags(w_real_top, WIN_FLAGS_CLIENT_STALE);
ps->pending_updates = true;
} else {
if (!w_real_top) {
log_debug("parent %#010x not found", ev->parent);
} else {
// Window is not currently mapped, unmark its
// client to trigger a client recheck when it is
// mapped later.
win_unmark_client(ps, w_real_top);
log_debug("parent %#010x (%s) is in state %d",
w_real_top->base.id, w_real_top->name,
w_real_top->state);
}
log_debug("parent %#010x not found", ev->parent);

Check warning on line 413 in src/event.c

View check run for this annotation

Codecov / codecov/patch

src/event.c#L413

Added line #L413 was not covered by tests
}
}
XCB_AWAIT_VOID(xcb_change_window_attributes, ps->c.c, ev->window,
Expand Down Expand Up @@ -605,7 +619,7 @@

static inline void repair_win(session_t *ps, struct managed_win *w) {
// Only mapped window can receive damages
assert(win_is_mapped_in_x(w));
assert(w->state == WSTATE_MAPPED || win_check_flags_all(w, WIN_FLAGS_MAPPED));

region_t parts;
pixman_region32_init(&parts);
Expand All @@ -628,6 +642,10 @@
free(e);
}
win_extents(w, &parts);

// We only binds the window pixmap once the window is damaged.
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE);
ps->pending_updates = true;
} else {
auto cookie = xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE,
ps->damage_ring.x_region);
Expand Down
2 changes: 1 addition & 1 deletion src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ base_deps = [
srcs = [ files('picom.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'vsync.c', 'utils.c',
'diagnostic.c', 'string_utils.c', 'render.c', 'kernel.c', 'log.c',
'options.c', 'event.c', 'cache.c', 'atom.c', 'file_watch.c', 'statistics.c',
'vblank.c') ]
'vblank.c', 'transition.c') ]
picom_inc = include_directories('.')

cflags = []
Expand Down
Loading