683 lines
20 KiB
Diff
683 lines
20 KiB
Diff
diff --git a/picom.sample.conf b/picom.sample.conf
|
|
index 777cf0d0..b7b10626 100644
|
|
--- a/picom.sample.conf
|
|
+++ b/picom.sample.conf
|
|
@@ -1,3 +1,42 @@
|
|
+#################################
|
|
+# Transitions #
|
|
+#################################
|
|
+
|
|
+# When windows get moved or resized it transitions window position
|
|
+transition = true;
|
|
+
|
|
+# How many pixels move window to make the first position in transition (defaults to 20)
|
|
+transition-offset = 20;
|
|
+
|
|
+# Direction of transition (top, right, bottom, left) e.g: "right" direction will make
|
|
+# all windows come from right to left
|
|
+
|
|
+# (smart-x, smart-y) are smart direction that will check if there are
|
|
+# multiple windows that splits the screen and will change their directions,
|
|
+# in "smart-x" it changes direction of left window to "right" and direction of
|
|
+# right window to "left", if screen is not splited and a window is taking
|
|
+# a lot of screen it will change that window direction to "left".
|
|
+# "smart-y" is also exactly like "smart-x" but instead of translating directions to
|
|
+# "right" and "left", it translate to "top" and "bottom"
|
|
+transition-direction = "smart-x";
|
|
+
|
|
+# Function that calculates new position of window (defaults to "ease-out-cubic")
|
|
+# see https://easings.net for list of all functions
|
|
+# naming conventions are different to that site tho, e.g "easeInSine" is listed
|
|
+# on site but here that translated to "ease-in-sine"
|
|
+transition-timing-function = "ease-out-cubic";
|
|
+
|
|
+# Time between frames in transition. (0.01 - 1.0, defaults to 0.028)
|
|
+transition-step = 0.028;
|
|
+
|
|
+# Similar to opacity rules but determites transition direction e.g:
|
|
+# "right: name *= 'Firefox'" will make firefox transition direction to right
|
|
+# Specify a list of transition rules, in the format `DIRECTION:PATTERN`
|
|
+
|
|
+# for disabling transition on specific patterns use "none" keyword as a direction
|
|
+# e.g: use "none: window_type = 'popup_menu'" for disabling transitions on popup menus
|
|
+transition-rule = [];
|
|
+
|
|
#################################
|
|
# Shadows #
|
|
#################################
|
|
diff --git a/src/config.c b/src/config.c
|
|
index 90324778..ae400c1b 100644
|
|
--- a/src/config.c
|
|
+++ b/src/config.c
|
|
@@ -579,6 +579,11 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
|
|
|
|
.track_leader = false,
|
|
|
|
+ .transition_offset = 20,
|
|
+ .transition_direction = 0,
|
|
+ .transition_step = 0.028,
|
|
+ .transition_timing_function = ease_out_cubic,
|
|
+
|
|
.rounded_corners_blacklist = NULL
|
|
};
|
|
// clang-format on
|
|
diff --git a/src/config.h b/src/config.h
|
|
index 03ef74b3..4cefb4c1 100644
|
|
--- a/src/config.h
|
|
+++ b/src/config.h
|
|
@@ -26,6 +26,8 @@
|
|
#include "types.h"
|
|
#include "win_defs.h"
|
|
|
|
+#include "timing_functions.h"
|
|
+
|
|
typedef struct session session_t;
|
|
|
|
/// @brief Possible backends
|
|
@@ -68,6 +70,18 @@ enum blur_method {
|
|
BLUR_METHOD_INVALID,
|
|
};
|
|
|
|
+enum transition_direction {
|
|
+ TRANSITION_DIR_NONE = 0,
|
|
+ TRANSITION_DIR_LEFT,
|
|
+ TRANSITION_DIR_BOTTOM,
|
|
+ TRANSITION_DIR_RIGHT,
|
|
+ TRANSITION_DIR_TOP,
|
|
+ TRANSITION_DIR_SMART_X,
|
|
+ TRANSITION_DIR_SMART_Y,
|
|
+};
|
|
+
|
|
+typedef double (*timing_function)(double);
|
|
+
|
|
typedef struct _c2_lptr c2_lptr_t;
|
|
|
|
/// Structure representing all options.
|
|
@@ -246,6 +260,22 @@ typedef struct options {
|
|
// Make transparent windows clip other windows, instead of blending on top of
|
|
// them
|
|
bool transparent_clipping;
|
|
+
|
|
+ // === Transition ===
|
|
+ // How many pixels move window to make the first position in transition
|
|
+ int transition_offset;
|
|
+
|
|
+ // Direction of transition
|
|
+ enum transition_direction transition_direction;
|
|
+
|
|
+ // Rules to change window transition
|
|
+ c2_lptr_t *transition_rules;
|
|
+
|
|
+ // Function that calculate new position
|
|
+ timing_function transition_timing_function;
|
|
+
|
|
+ // Time between frames in transition
|
|
+ double transition_step;
|
|
} options_t;
|
|
|
|
extern const char *const BACKEND_STRS[NUM_BKEND + 1];
|
|
diff --git a/src/config_libconfig.c b/src/config_libconfig.c
|
|
index e9818ebc..60e72a86 100644
|
|
--- a/src/config_libconfig.c
|
|
+++ b/src/config_libconfig.c
|
|
@@ -295,6 +295,90 @@ static inline void parse_wintype_config(const config_t *cfg, const char *member_
|
|
}
|
|
}
|
|
|
|
+enum transition_direction parse_transition_direction(const char *direction) {
|
|
+ static const char *names[] = {"none", "left", "bottom", "right",
|
|
+ "top", "smart-x", "smart-y"};
|
|
+
|
|
+ for (unsigned int i = 0; i < sizeof(names) / sizeof(char *); i++) {
|
|
+ if (strcmp(direction, names[i]) == 0) {
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ log_error("'%s' is not a valid transition direction.", direction);
|
|
+ return TRANSITION_DIR_NONE;
|
|
+}
|
|
+
|
|
+timing_function parse_timing_function(const char *timing_name) {
|
|
+ // clang-format off
|
|
+ static const char *names[] = {
|
|
+ "sine", "cubic", "quint", "circ", "elastic",
|
|
+ "quad", "quart", "etpo", "back", "bounce"
|
|
+ };
|
|
+
|
|
+ static const char *prefixes[] = {"in", "out", "in-out"};
|
|
+
|
|
+ static timing_function functions[] = {
|
|
+ ease_in_sine , ease_out_sine , ease_in_out_sine ,
|
|
+ ease_in_cubic , ease_out_cubic , ease_in_out_cubic ,
|
|
+ ease_in_quint , ease_out_quint , ease_in_out_quint ,
|
|
+ ease_in_circ , ease_out_circ , ease_in_out_circ ,
|
|
+ ease_in_elastic, ease_out_elastic, ease_in_out_elastic,
|
|
+ ease_in_quad , ease_out_quad , ease_in_out_quad ,
|
|
+ ease_in_quart , ease_out_quart , ease_in_out_quart ,
|
|
+ ease_in_etpo , ease_out_etpo , ease_in_out_etpo ,
|
|
+ ease_in_back , ease_out_back , ease_in_out_back ,
|
|
+ ease_in_bounce , ease_out_bounce , ease_in_out_bounce ,
|
|
+ };
|
|
+ // clang-format on
|
|
+
|
|
+ char buffer[64];
|
|
+ for (unsigned int i = 0; i < sizeof(names) / sizeof(char *); i++) {
|
|
+ for (unsigned int p = 0; p < 3; p++) {
|
|
+ snprintf(buffer, sizeof(buffer), "ease-%s-%s", prefixes[p], names[i]);
|
|
+
|
|
+ if (strcmp(buffer, timing_name) == 0) {
|
|
+ unsigned int function_index = (i * 3) + p;
|
|
+ return functions[function_index];
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ log_error("'%s' is not a valid transition timing function.", timing_name);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static inline void
|
|
+parse_cfg_condlst_trns(options_t *opt, const config_t *pcfg, const char *name) {
|
|
+ config_setting_t *setting = config_lookup(pcfg, name);
|
|
+ if (setting) {
|
|
+ int length = config_setting_length(setting);
|
|
+
|
|
+ for (int i = 0; i < length; i++) {
|
|
+ const char *elem = config_setting_get_string_elem(setting, i);
|
|
+
|
|
+ char rule[512];
|
|
+ unsigned long elem_index = 0;
|
|
+
|
|
+ for (int rule_index = 0; elem_index < strlen(elem); elem_index++) {
|
|
+ char character = elem[elem_index];
|
|
+ if (character == ':') {
|
|
+ rule[rule_index] = '\0';
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (!isspace(character)) {
|
|
+ rule[rule_index] = character;
|
|
+ rule_index++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ int *direction = (int *)parse_transition_direction(rule);
|
|
+ c2_parse(&opt->transition_rules, &elem[elem_index + 1], direction);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* Parse a configuration file from default location.
|
|
*
|
|
@@ -642,6 +726,28 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
|
opt->write_pid_path = strdup(sval);
|
|
}
|
|
|
|
+ // Transition
|
|
+ if (lcfg_lookup_bool(&cfg, "transition", &bval)) {
|
|
+ if (bval) {
|
|
+ config_lookup_int(&cfg, "transition-offset", &opt->transition_offset);
|
|
+ config_lookup_float(&cfg, "transition-step", &opt->transition_step);
|
|
+
|
|
+ if (config_lookup_string(&cfg, "transition-direction", &sval)) {
|
|
+ opt->transition_direction = parse_transition_direction(sval);
|
|
+ }
|
|
+
|
|
+ if (config_lookup_string(&cfg, "transition-timing-function", &sval)) {
|
|
+ timing_function res = parse_timing_function(sval);
|
|
+
|
|
+ if (res != NULL) {
|
|
+ opt->transition_timing_function = res;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ parse_cfg_condlst_trns(opt, &cfg, "transition-rule");
|
|
+ }
|
|
+ }
|
|
+
|
|
// Wintype settings
|
|
|
|
// XXX ! Refactor all the wintype_* arrays into a struct
|
|
diff --git a/src/event.c b/src/event.c
|
|
index e6052f1d..f9ca356a 100644
|
|
--- a/src/event.c
|
|
+++ b/src/event.c
|
|
@@ -186,6 +186,10 @@ static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev
|
|
}
|
|
}
|
|
|
|
+static inline unsigned int distance(int x1, int x2, int y1, int y2) {
|
|
+ return (unsigned int)(abs(x2 - x1) + abs(y2 - y1));
|
|
+}
|
|
+
|
|
/// Handle configure event of a regular window
|
|
static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|
auto w = find_win(ps, ce->window);
|
|
@@ -217,6 +221,15 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|
// visible/mapped
|
|
ps->pending_updates = true;
|
|
|
|
+ static const unsigned int small_diff = 100;
|
|
+ bool small_move =
|
|
+ position_changed &&
|
|
+ distance(mw->pending_g.x, ce->x, mw->pending_g.y, ce->y) < small_diff;
|
|
+
|
|
+ bool small_resize =
|
|
+ size_changed && distance(mw->pending_g.width, ce->width,
|
|
+ mw->pending_g.height, ce->height) < small_diff;
|
|
+
|
|
// At least one of the following if's is true
|
|
if (position_changed) {
|
|
log_trace("Window position changed, %dx%d -> %dx%d", mw->g.x,
|
|
@@ -235,6 +248,20 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|
win_set_flags(mw, WIN_FLAGS_SIZE_STALE);
|
|
}
|
|
|
|
+ if (mw->transition_direction != TRANSITION_DIR_NONE) {
|
|
+ // Dont't transition windows that wanna go out of screen
|
|
+ if (ce->x >= 0 && ce->x <= ps->root_width) {
|
|
+ mw->transition_time = 0.0f;
|
|
+ mw->target_geometry = mw->pending_g;
|
|
+ } else {
|
|
+ mw->transition_time = -1.0f;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (mw->transition_time != -1.0f && (small_move || small_resize)) {
|
|
+ mw->transition_time = -1.0f;
|
|
+ }
|
|
+
|
|
// Recalculate which screen this window is on
|
|
win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, mw);
|
|
}
|
|
diff --git a/src/meson.build b/src/meson.build
|
|
index 0a882f93..341df783 100644
|
|
--- a/src/meson.build
|
|
+++ b/src/meson.build
|
|
@@ -9,7 +9,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') ]
|
|
+ 'options.c', 'event.c', 'cache.c', 'atom.c', 'file_watch.c', 'timing_functions.c') ]
|
|
picom_inc = include_directories('.')
|
|
|
|
cflags = []
|
|
diff --git a/src/picom.c b/src/picom.c
|
|
index 81fb334d..2c9a42ad 100644
|
|
--- a/src/picom.c
|
|
+++ b/src/picom.c
|
|
@@ -680,6 +680,51 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
|
|
if (was_painted && w->mode != mode_old) {
|
|
w->reg_ignore_valid = false;
|
|
}
|
|
+
|
|
+ // Transition
|
|
+ bool valid_trns_time = w->transition_time >= 0.0f && w->transition_time <= 1.0f;
|
|
+ if (w->transition_direction && valid_trns_time) {
|
|
+ double transition =
|
|
+ ps->o.transition_timing_function(w->transition_time);
|
|
+
|
|
+ w->transition_time += ps->o.transition_step;
|
|
+ if (w->transition_time > 1.0f)
|
|
+ transition = 1.0f;
|
|
+
|
|
+ add_damage_from_win(ps, w);
|
|
+ unsigned int direction = w->transition_direction;
|
|
+
|
|
+ // Smart direction
|
|
+ if (direction == TRANSITION_DIR_SMART_X ||
|
|
+ direction == TRANSITION_DIR_SMART_Y) {
|
|
+
|
|
+ bool wide_enough = w->g.width > 80 * ps->root_width / 100;
|
|
+ bool bigger_than_half =
|
|
+ w->target_geometry.x > ps->root_width / 2;
|
|
+
|
|
+ /*
|
|
+ Not changing transition_direction because
|
|
+ smart calculation have to be calculated each time
|
|
+ */
|
|
+ direction = w->transition_direction -
|
|
+ ((bigger_than_half || wide_enough) ? 4 : 2);
|
|
+ }
|
|
+
|
|
+ // Determite we are working on x or y of window
|
|
+ int8_t xy = !(direction % 2);
|
|
+
|
|
+ int16_t xy_target = *(((int16_t *)&w->target_geometry) + xy);
|
|
+ int16_t *xy_source = ((int16_t *)&w->g) + xy;
|
|
+
|
|
+ int8_t sign = (direction - 1) % 3 ? 1 : -1;
|
|
+ int start_location = xy_target + sign * ps->o.transition_offset;
|
|
+
|
|
+ *xy_source = (int16_t)round(
|
|
+ transition * (xy_target - start_location) + start_location);
|
|
+
|
|
+ w->mode = WMODE_TRANS;
|
|
+ *fade_running = true;
|
|
+ }
|
|
}
|
|
|
|
// Opacity will not change, from now on.
|
|
@@ -1804,6 +1849,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|
c2_list_postprocess(ps, ps->o.invert_color_list) &&
|
|
c2_list_postprocess(ps, ps->o.opacity_rules) &&
|
|
c2_list_postprocess(ps, ps->o.rounded_corners_blacklist) &&
|
|
+ c2_list_postprocess(ps, ps->o.transition_rules) &&
|
|
c2_list_postprocess(ps, ps->o.focus_blacklist))) {
|
|
log_error("Post-processing of conditionals failed, some of your rules "
|
|
"might not work");
|
|
@@ -2174,6 +2220,7 @@ static void session_destroy(session_t *ps) {
|
|
free_wincondlst(&ps->o.paint_blacklist);
|
|
free_wincondlst(&ps->o.unredir_if_possible_blacklist);
|
|
free_wincondlst(&ps->o.rounded_corners_blacklist);
|
|
+ free_wincondlst(&ps->o.transition_rules);
|
|
|
|
// Free tracked atom list
|
|
{
|
|
diff --git a/src/timing_functions.c b/src/timing_functions.c
|
|
new file mode 100644
|
|
index 00000000..a6424bd2
|
|
--- /dev/null
|
|
+++ b/src/timing_functions.c
|
|
@@ -0,0 +1,178 @@
|
|
+#include "timing_functions.h"
|
|
+#include <math.h>
|
|
+
|
|
+// clang-format off
|
|
+double ease_in_sine(double t) {
|
|
+ return 1 - cos((t * M_PI) / 2);
|
|
+}
|
|
+
|
|
+double ease_out_sine(double t) {
|
|
+ return sin((t * M_PI) / 2);
|
|
+}
|
|
+
|
|
+double ease_in_out_sine(double t) {
|
|
+ return -(cos(M_PI * t) - 1) / 2;
|
|
+}
|
|
+
|
|
+double ease_in_cubic(double t) {
|
|
+ return t * t * t;
|
|
+}
|
|
+
|
|
+double ease_out_cubic(double t) {
|
|
+ return 1 - pow(1 - t, 3);
|
|
+}
|
|
+
|
|
+double ease_in_out_cubic(double t) {
|
|
+ return t < 0.5 ? 4 * t * t * t : 1 - pow(-2 * t + 2, 3) / 2;
|
|
+}
|
|
+
|
|
+double ease_in_quint(double t) {
|
|
+ return t * t * t * t * t;
|
|
+}
|
|
+
|
|
+double ease_out_quint(double t) {
|
|
+ return 1 - pow(1 - t, 5);
|
|
+}
|
|
+
|
|
+double ease_in_out_quint(double t) {
|
|
+ return t < 0.5 ? 16 * t * t * t * t * t : 1 - pow(-2 * t + 2, 5) / 2;
|
|
+}
|
|
+
|
|
+double ease_in_circ(double t) {
|
|
+ return 1 - sqrt(1 - pow(t, 2));
|
|
+}
|
|
+
|
|
+double ease_out_circ(double t) {
|
|
+ return sqrt(1 - pow(t - 1, 2));
|
|
+}
|
|
+
|
|
+double ease_in_out_circ(double t) {
|
|
+ return t < 0.5
|
|
+ ? (1 - sqrt(1 - pow(2 * t, 2))) / 2
|
|
+ : (sqrt(1 - pow(-2 * t + 2, 2)) + 1) / 2;
|
|
+}
|
|
+
|
|
+double ease_in_elastic(double t) {
|
|
+ double c4 = (2 * M_PI) / 3;
|
|
+
|
|
+ return t == 0
|
|
+ ? 0
|
|
+ : t == 1
|
|
+ ? 1
|
|
+ : -pow(2, 10 * t - 10) * sin((t * 10 - 10.75) * c4);
|
|
+}
|
|
+
|
|
+double ease_out_elastic(double t) {
|
|
+ double c4 = (2 * M_PI) / 3;
|
|
+
|
|
+ return t == 0
|
|
+ ? 0
|
|
+ : t == 1
|
|
+ ? 1
|
|
+ : pow(2, -10 * t) * sin((t * 10 - 0.75) * c4) + 1;
|
|
+}
|
|
+
|
|
+double ease_in_out_elastic(double t) {
|
|
+ double c5 = (2 * M_PI) / 4.5;
|
|
+
|
|
+ return t == 0
|
|
+ ? 0
|
|
+ : t == 1
|
|
+ ? 1
|
|
+ : t < 0.5
|
|
+ ? -(pow(2, 20 * t - 10) * sin((20 * t - 11.125) * c5)) / 2
|
|
+ : (pow(2, -20 * t + 10) * sin((20 * t - 11.125) * c5)) / 2 + 1;
|
|
+}
|
|
+
|
|
+double ease_in_quad(double t) {
|
|
+ return t * t;
|
|
+}
|
|
+
|
|
+double ease_out_quad(double t) {
|
|
+ return 1 - (1 - t) * (1 - t);
|
|
+}
|
|
+
|
|
+double ease_in_out_quad(double t) {
|
|
+ return t < 0.5 ? 2 * t * t : 1 - pow(-2 * t + 2, 2) / 2;
|
|
+}
|
|
+
|
|
+double ease_in_quart(double t) {
|
|
+ return t * t * t * t;
|
|
+}
|
|
+
|
|
+double ease_out_quart(double t) {
|
|
+ return 1 - pow(1 - t, 4);
|
|
+}
|
|
+
|
|
+double ease_in_out_quart(double t) {
|
|
+ return t < 0.5 ? 8 * t * t * t * t : 1 - pow(-2 * t + 2, 4) / 2;
|
|
+}
|
|
+
|
|
+double ease_in_etpo(double t) {
|
|
+ return t == 0 ? 0 : pow(2, 10 * t - 10);
|
|
+}
|
|
+
|
|
+double ease_out_etpo(double t) {
|
|
+ return t == 1 ? 1 : 1 - pow(2, -10 * t);
|
|
+}
|
|
+
|
|
+double ease_in_out_etpo(double t) {
|
|
+ return t == 0
|
|
+ ? 0
|
|
+ : t == 1
|
|
+ ? 1
|
|
+ : t < 0.5 ? pow(2, 20 * t - 10) / 2
|
|
+ : (2 - pow(2, -20 * t + 10)) / 2;
|
|
+}
|
|
+
|
|
+double ease_in_back(double t) {
|
|
+ double c1 = 1.70158;
|
|
+ double c3 = c1 + 1;
|
|
+
|
|
+ return c3 * t * t * t - c1 * t * t;
|
|
+}
|
|
+
|
|
+double ease_out_back(double t) {
|
|
+ double c1 = 1.70158;
|
|
+ double c3 = c1 + 1;
|
|
+
|
|
+ return 1 + c3 * pow(t - 1, 3) + c1 * pow(t - 1, 2);
|
|
+}
|
|
+
|
|
+double ease_in_out_back(double t) {
|
|
+ double c1 = 1.70158;
|
|
+ double c2 = c1 * 1.525;
|
|
+
|
|
+ return t < 0.5
|
|
+ ? (pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
|
|
+ : (pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
|
|
+}
|
|
+
|
|
+double ease_in_bounce(double t) {
|
|
+ return 1 - ease_out_bounce(1 - t);
|
|
+}
|
|
+
|
|
+double ease_out_bounce(double t) {
|
|
+ double n1 = 7.5625;
|
|
+ double d1 = 2.75;
|
|
+
|
|
+ if (t < 1 / d1) {
|
|
+ return n1 * t * t;
|
|
+ } else if (t < 2 / d1) {
|
|
+ t -= 1.5 / d1;
|
|
+ return n1 * t * t + 0.75;
|
|
+ } else if (t < 2.5 / d1) {
|
|
+ t -= 2.25 / d1;
|
|
+ return n1 * t * t + 0.9375;
|
|
+ } else {
|
|
+ t -= 2.625 / d1;
|
|
+ return n1 * t * t + 0.984375;
|
|
+ }
|
|
+}
|
|
+
|
|
+double ease_in_out_bounce(double t) {
|
|
+ return t < 0.5
|
|
+ ? (1 - ease_out_bounce(1 - 2 * t)) / 2
|
|
+ : (1 + ease_out_bounce(2 * t - 1)) / 2;
|
|
+}
|
|
+// clang-format on
|
|
\ No newline at end of file
|
|
diff --git a/src/timing_functions.h b/src/timing_functions.h
|
|
new file mode 100644
|
|
index 00000000..8e6776e3
|
|
--- /dev/null
|
|
+++ b/src/timing_functions.h
|
|
@@ -0,0 +1,46 @@
|
|
+/*
|
|
+ all functions and formulas gathered from
|
|
+ https://easings.net/
|
|
+*/
|
|
+
|
|
+#pragma once
|
|
+
|
|
+double ease_in_sine(double t);
|
|
+double ease_out_sine(double t);
|
|
+double ease_in_out_sine(double t);
|
|
+
|
|
+double ease_in_cubic(double t);
|
|
+double ease_out_cubic(double t);
|
|
+double ease_in_out_cubic(double t);
|
|
+
|
|
+double ease_in_quint(double t);
|
|
+double ease_out_quint(double t);
|
|
+double ease_in_out_quint(double t);
|
|
+
|
|
+double ease_in_circ(double t);
|
|
+double ease_out_circ(double t);
|
|
+double ease_in_out_circ(double t);
|
|
+
|
|
+double ease_in_elastic(double t);
|
|
+double ease_out_elastic(double t);
|
|
+double ease_in_out_elastic(double t);
|
|
+
|
|
+double ease_in_quad(double t);
|
|
+double ease_out_quad(double t);
|
|
+double ease_in_out_quad(double t);
|
|
+
|
|
+double ease_in_quart(double t);
|
|
+double ease_out_quart(double t);
|
|
+double ease_in_out_quart(double t);
|
|
+
|
|
+double ease_in_etpo(double t);
|
|
+double ease_out_etpo(double t);
|
|
+double ease_in_out_etpo(double t);
|
|
+
|
|
+double ease_in_back(double t);
|
|
+double ease_out_back(double t);
|
|
+double ease_in_out_back(double t);
|
|
+
|
|
+double ease_out_bounce(double t);
|
|
+double ease_in_bounce(double t);
|
|
+double ease_in_out_bounce(double t);
|
|
\ No newline at end of file
|
|
diff --git a/src/win.c b/src/win.c
|
|
index 7bdb05f5..5171284f 100644
|
|
--- a/src/win.c
|
|
+++ b/src/win.c
|
|
@@ -1118,6 +1118,14 @@ void win_update_opacity_rule(session_t *ps, struct managed_win *w) {
|
|
w->opacity_is_set = is_set;
|
|
}
|
|
|
|
+void win_update_transition_rule(session_t *ps, struct managed_win *w) {
|
|
+ void *val;
|
|
+ if (c2_match(ps, w, ps->o.transition_rules, &val)) {
|
|
+ // uses multiple casters to trick compiler to not give warnings
|
|
+ w->transition_direction = (unsigned int)(long)val;
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* Function to be called on window data changes.
|
|
*
|
|
@@ -1129,6 +1137,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) {
|
|
// state of the window
|
|
win_update_focused(ps, w);
|
|
|
|
+ win_update_transition_rule(ps, w);
|
|
win_determine_shadow(ps, w);
|
|
win_determine_clip_shadow_above(ps, w);
|
|
win_determine_invert_color(ps, w);
|
|
@@ -1497,6 +1506,8 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
|
.shadow_paint = PAINT_INIT,
|
|
|
|
.corner_radius = 0,
|
|
+
|
|
+ .transition_time = -1.0f,
|
|
};
|
|
|
|
assert(!w->destroyed);
|
|
@@ -1568,6 +1579,8 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
|
.border_width = g->border_width,
|
|
};
|
|
|
|
+ new->transition_direction = ps->o.transition_direction;
|
|
+
|
|
free(g);
|
|
|
|
// Create Damage for window (if not Input Only)
|
|
diff --git a/src/win.h b/src/win.h
|
|
index 6c6ae323..2a5779c0 100644
|
|
--- a/src/win.h
|
|
+++ b/src/win.h
|
|
@@ -270,6 +270,15 @@ struct managed_win {
|
|
/// Whether to blur window background.
|
|
bool blur_background;
|
|
|
|
+ /// Transition time that used as input in timing function
|
|
+ double transition_time;
|
|
+
|
|
+ /// Save new geometry for calculating transition
|
|
+ struct win_geometry target_geometry;
|
|
+
|
|
+ /// Transition direction of window
|
|
+ enum transition_direction transition_direction;
|
|
+
|
|
#ifdef CONFIG_OPENGL
|
|
/// Textures and FBO background blur use.
|
|
glx_blur_cache_t glx_blur_cache;
|