From df7037d82b107afa2210e16e3a67075b70ecc40e Mon Sep 17 00:00:00 2001 From: Monsterovich Date: Tue, 10 Sep 2024 03:58:31 +0200 Subject: [PATCH] wm: split geometry trigger into size and position And keep geometry as an alias for setting both size and position. Changelog: NewFeature: Separate the "geometry" animation trigger into "size" and "position" to allow finer-grained control. "geometry" is kept as an alias for setting both "size" and "position". Co-authored-by: Monsterovich Signed-off-by: Yuxuan Shui --- man/picom.1.adoc | 6 ++++-- src/config.h | 15 ++++++++++++--- src/config_libconfig.c | 11 +++++++++++ src/wm/win.c | 18 ++++++++++++------ src/wm/win.h | 15 ++++++++++++--- 5 files changed, 51 insertions(+), 14 deletions(-) diff --git a/man/picom.1.adoc b/man/picom.1.adoc index 81bd2804..7ae4bd1e 100644 --- a/man/picom.1.adoc +++ b/man/picom.1.adoc @@ -509,9 +509,11 @@ animations = ({ _decrease-opacity_:: When the opacity of a window is decreased. - [[trigger-geometry]]_geometry_:: When the geometry of a window is changed. (EXPERIMENTAL) + _size_, _position_:: When the size or position of a window is changed. If both changed, the position trigger has priority. (EXPERIMENTAL) + + [[trigger-geometry]]_geometry_:: Alias of size + position. + -WARNING: The _geometry_ trigger is experimental. Using this means you accept the caveat that geometry animations will also trigger when you manually resize or move a window, like when you drag the window around with your mouse. +WARNING: The _size_ and _position_ triggers are experimental. Using this means you accept the caveat that these animations will also trigger when you manually resize or move a window, like when you drag the window around with your mouse. _suppressions_::: Which other animations should be suppressed when this animation is running. Normally, if another trigger is activated while an animation is already running, the animation in progress will be interrupted and the new animation will start. If you want to prevent this, you can set the `suppressions` option to a list of triggers that should be suppressed. This is optional, the default value for this is an empty list. diff --git a/src/config.h b/src/config.h index df7d39fc..2f691bc4 100644 --- a/src/config.h +++ b/src/config.h @@ -73,11 +73,18 @@ enum animation_trigger { ANIMATION_TRIGGER_OPEN, /// When a window is closed ANIMATION_TRIGGER_CLOSE, - /// When a window's geometry changes - ANIMATION_TRIGGER_GEOMETRY, + /// When a window's size changes + ANIMATION_TRIGGER_SIZE, + /// When a window's position changes + ANIMATION_TRIGGER_POSITION, ANIMATION_TRIGGER_INVALID, ANIMATION_TRIGGER_COUNT = ANIMATION_TRIGGER_INVALID, + + // Aliases are not included in the count + + /// Alias of size + position + ANIMATION_TRIGGER_ALIAS_GEOMETRY, }; static const char *animation_trigger_names[] attr_unused = { @@ -87,7 +94,9 @@ static const char *animation_trigger_names[] attr_unused = { [ANIMATION_TRIGGER_DECREASE_OPACITY] = "decrease-opacity", [ANIMATION_TRIGGER_OPEN] = "open", [ANIMATION_TRIGGER_CLOSE] = "close", - [ANIMATION_TRIGGER_GEOMETRY] = "geometry", + [ANIMATION_TRIGGER_SIZE] = "size", + [ANIMATION_TRIGGER_POSITION] = "position", + [ANIMATION_TRIGGER_ALIAS_GEOMETRY] = "geometry", }; struct script; diff --git a/src/config_libconfig.c b/src/config_libconfig.c index 35709128..0356d373 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -363,6 +363,17 @@ static bool parse_animation_one(struct win_script *animations, log_error("Invalid trigger defined at line %d", config_setting_source_line(triggers)); } + if ((trigger_types & (1 << ANIMATION_TRIGGER_ALIAS_GEOMETRY)) != 0) { + const uint64_t to_set = + (1 << ANIMATION_TRIGGER_SIZE) | (1 << ANIMATION_TRIGGER_POSITION); + if ((trigger_types & to_set) != 0) { + log_warn("Trigger \"geometry\" is an alias of \"size\" and " + "\"position\", but one or both of them are also set at " + "line %d", + config_setting_source_line(triggers)); + } + trigger_types |= to_set; + } // script parser shouldn't see this. config_setting_remove(setting, "triggers"); diff --git a/src/wm/win.c b/src/wm/win.c index 26a24fee..6608feeb 100644 --- a/src/wm/win.c +++ b/src/wm/win.c @@ -1715,7 +1715,10 @@ bool win_process_animation_and_state_change(struct session *ps, struct win *w, d bool will_never_render = (!w->ever_damaged || w->win_image == NULL) && w->state != WSTATE_MAPPED; auto win_ctx = win_script_context_prepare(ps, w); - bool geometry_changed = !win_geometry_eq(w->previous.g, w->g); + + bool size_changed = win_size_changed(w->previous.g, w->g); + bool position_changed = win_position_changed(w->previous.g, w->g); + auto old_state = w->previous.state; w->previous.state = w->state; @@ -1726,7 +1729,7 @@ bool win_process_animation_and_state_change(struct session *ps, struct win *w, d // This window won't be rendered, so we don't need to run the animations. bool state_changed = old_state != w->state || win_ctx.opacity_before != win_ctx.opacity || - geometry_changed; + size_changed || position_changed; return state_changed || (w->running_animation_instance != NULL); } @@ -1741,7 +1744,7 @@ bool win_process_animation_and_state_change(struct session *ps, struct win *w, d enum animation_trigger trigger = ANIMATION_TRIGGER_INVALID; // Animation trigger priority: - // state > geometry > opacity + // state > position > size > opacity if (old_state != w->state) { // Send D-Bus signal if (ps->o.dbus) { @@ -1786,9 +1789,12 @@ bool win_process_animation_and_state_change(struct session *ps, struct win *w, d assert(false); return true; } - } else if (geometry_changed) { + } else if (position_changed) { assert(w->state == WSTATE_MAPPED); - trigger = ANIMATION_TRIGGER_GEOMETRY; + trigger = ANIMATION_TRIGGER_POSITION; + } else if (size_changed) { + assert(w->state == WSTATE_MAPPED); + trigger = ANIMATION_TRIGGER_SIZE; } else if (win_ctx.opacity_before != win_ctx.opacity) { assert(w->state == WSTATE_MAPPED); trigger = win_ctx.opacity > win_ctx.opacity_before @@ -1877,7 +1883,7 @@ bool win_process_animation_and_state_change(struct session *ps, struct win *w, d memory[output_indices[WIN_SCRIPT_SAVED_IMAGE_BLEND]] = 1 - memory[output_indices[WIN_SCRIPT_SAVED_IMAGE_BLEND]]; } - if (geometry_changed) { + if (size_changed || position_changed) { // If the window has moved, we need to adjust scripts // outputs so that the window will stay in the same position and // size after applying the animation. This way the window's size diff --git a/src/wm/win.h b/src/wm/win.h index 5dc503b1..22fe6b76 100644 --- a/src/wm/win.h +++ b/src/wm/win.h @@ -353,10 +353,19 @@ win_options(const struct win *w) { win_maybe_options_fold(w->options_override, w->options), *w->options_default); } -/// Check if win_geometry `a` and `b` have the same sizes and positions. Border width is +/// Check if the window has changed in size. Border width is /// not considered. -static inline bool win_geometry_eq(struct win_geometry a, struct win_geometry b) { - return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height; +static inline bool win_size_changed(struct win_geometry a, struct win_geometry b) { + return a.width != b.width || a.height != b.height; +} + +/// Check if the window position has changed. +static inline bool win_position_changed(struct win_geometry a, struct win_geometry b) { + if (win_size_changed(a, b)) { + return false; + } + + return a.x != b.x || a.y != b.y; } /// Process pending updates/images flags on a window. Has to be called in X critical