Skip to content

Commit

Permalink
Merge branch 'yshui:next' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
pijulius committed May 20, 2024
2 parents cee741a + 1e6962f commit 17d048c
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 85 deletions.
3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ jobs:
- run:
name: test config file parsing
command: xvfb-run -s "-screen 0 640x480x24" build/src/picom --config tests/configs/parsing_test.conf --no-vsync --diagnostics
- run:
name: test config file parsing in a different locale
command: LC_NUMERIC=de_DE.UTF-8 xvfb-run -s "-screen 0 640x480x24" build/src/picom --config tests/configs/parsing_test.conf --no-vsync --diagnostics
- run:
name: run testsuite
command: tests/run_tests.sh build/src/picom
Expand Down
3 changes: 2 additions & 1 deletion src/backend/backend_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ bool build_shadow(struct x_connection *c, double opacity, const int width,
batch_height = to_u16_checked(shadow_image->height - row);
}

uint32_t offset = row * shadow_image->stride / sizeof(*shadow_image->data);
auto offset =
(size_t)row * shadow_image->stride / sizeof(*shadow_image->data);
xcb_put_image(c->c, (uint8_t)shadow_image->format, shadow_pixmap, gc,
shadow_image->width, batch_height, 0, to_i16_checked(row),
0, shadow_image->depth, shadow_image->stride * batch_height,
Expand Down
13 changes: 3 additions & 10 deletions src/backend/xrender/xrender.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,6 @@ xrender_copy_area(struct backend_base *base, ivec2 origin, image_handle target_h
static bool xrender_blur(struct backend_base *base, ivec2 origin,
image_handle target_handle, const struct backend_blur_args *args) {
auto bctx = (struct xrender_blur_context *)args->blur_context;
auto source_mask = args->source_image
? (struct xrender_image_data_inner *)args->source_mask->image
: NULL;
auto source = (struct xrender_image_data_inner *)args->source_image;
auto target = (struct xrender_image_data_inner *)target_handle;
if (bctx->method == BLUR_METHOD_NONE) {
Expand Down Expand Up @@ -547,22 +544,18 @@ static bool xrender_blur(struct backend_base *base, ivec2 origin,
xcb_render_picture_t src_pict = source->pict;
auto mask_pict = xd->alpha_pict[(int)(args->opacity * MAX_ALPHA)];
bool mask_allocated = false;
auto mask_pict_origin = args->source_mask->origin;
if (source_mask != NULL) {
ivec2 mask_pict_origin = {};
if (args->source_mask != NULL) {
// Translate the target mask region to the mask's coordinate
auto mask_extent = *pixman_region32_extents(args->target_mask);
region_translate_rect(
mask_extent, ivec2_neg(ivec2_add(origin, args->source_mask->origin)));
mask_pict_origin = args->source_mask->origin;
mask_pict = xrender_process_mask(xd, args->source_mask, mask_extent,
args->opacity != 1.0 ? mask_pict : XCB_NONE,
&mask_pict_origin, &mask_allocated);
mask_pict_origin.x -= extent_resized->x1;
mask_pict_origin.y -= extent_resized->y1;
} else {
// Sampling the 1x1 alpha pict out-of-bound while the X server is under
// heavy load, which it will be if blur is enabled, produces unpredictable
// results... This is a workaround for that.
mask_pict_origin = (ivec2){0, 0};
}
x_set_picture_clip_region(c, src_pict, 0, 0, &reg_op_resized);
x_set_picture_clip_region(c, target->pict, 0, 0, args->target_mask);
Expand Down
139 changes: 78 additions & 61 deletions src/config_libconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,21 +407,22 @@ static struct script **parse_animations(struct win_script *animations,

#define FADING_TEMPLATE_1 \
"opacity = { " \
" timing = \"%fms linear\"; " \
" timing = \"%sms linear\"; " \
" start = \"window-raw-opacity-before\"; " \
" end = \"window-raw-opacity\"; " \
"};" \
"shadow-opacity = \"opacity\";"
#define FADING_TEMPLATE_2 \
"blur-opacity = { " \
" timing = \"%fms linear\"; " \
" start = %f; end = %f; " \
" timing = \"%sms linear\"; " \
" start = %d; end = %d; " \
"};"

static struct script *compile_win_script_from_string(const char *input, int *output_indices) {
config_t tmp_config;
config_setting_t *setting;
config_init(&tmp_config);
config_set_auto_convert(&tmp_config, true);
config_read_string(&tmp_config, input);
setting = config_root_setting(&tmp_config);

Expand All @@ -437,7 +438,7 @@ static struct script *compile_win_script_from_string(const char *input, int *out
void generate_fading_config(struct options *opt) {
// We create stand-in animations for fade-in/fade-out if they haven't be
// overwritten
char *str = NULL;
scoped_charp str = NULL;
size_t len = 0;
enum animation_trigger trigger[2];
struct script *scripts[4];
Expand All @@ -446,72 +447,88 @@ void generate_fading_config(struct options *opt) {

int output_indices[NUM_OF_WIN_SCRIPT_OUTPUTS];
double duration = 1.0 / opt->fade_in_step * opt->fade_delta;
// Fading in from nothing, i.e. `open` and `show`
asnprintf(&str, &len, FADING_TEMPLATE_1 FADING_TEMPLATE_2, duration, duration,
0.F, 1.F);
if (!safe_isinf(duration) && !safe_isnan(duration) && duration > 0) {
scoped_charp duration_str = NULL;
dtostr(duration, &duration_str);

auto fade_in1 = compile_win_script_from_string(str, output_indices);
if (opt->animations[ANIMATION_TRIGGER_OPEN].script == NULL && !opt->no_fading_openclose) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_OPEN;
}
if (opt->animations[ANIMATION_TRIGGER_SHOW].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_SHOW;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_in1,
output_indices, 0, 0)) {
scripts[number_of_scripts++] = fade_in1;
} else {
script_free(fade_in1);
}
// Fading in from nothing, i.e. `open` and `show`
asnprintf(&str, &len, FADING_TEMPLATE_1 FADING_TEMPLATE_2, duration_str,
duration_str, 0, 1);

// Fading for opacity change, for these, the blur opacity doesn't change.
asnprintf(&str, &len, FADING_TEMPLATE_1, duration);
auto fade_in2 = compile_win_script_from_string(str, output_indices);
number_of_triggers = 0;
if (opt->animations[ANIMATION_TRIGGER_INCREASE_OPACITY].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_INCREASE_OPACITY;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_in2,
output_indices, 0, 0)) {
scripts[number_of_scripts++] = fade_in2;
auto fade_in1 = compile_win_script_from_string(str, output_indices);
if (opt->animations[ANIMATION_TRIGGER_OPEN].script == NULL &&
!opt->no_fading_openclose) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_OPEN;
}
if (opt->animations[ANIMATION_TRIGGER_SHOW].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_SHOW;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_in1,
output_indices, 0, 0)) {
scripts[number_of_scripts++] = fade_in1;
} else {
script_free(fade_in1);
}

// Fading for opacity change, for these, the blur opacity doesn't change.
asnprintf(&str, &len, FADING_TEMPLATE_1, duration_str);
auto fade_in2 = compile_win_script_from_string(str, output_indices);
number_of_triggers = 0;
if (opt->animations[ANIMATION_TRIGGER_INCREASE_OPACITY].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_INCREASE_OPACITY;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_in2,
output_indices, 0, 0)) {
scripts[number_of_scripts++] = fade_in2;
} else {
script_free(fade_in2);
}
} else {
script_free(fade_in2);
log_error("Invalid fade-in setting (step: %f, delta: %d), ignoring.",
opt->fade_in_step, opt->fade_delta);
}

duration = 1.0 / opt->fade_out_step * opt->fade_delta;
// Fading out to nothing, i.e. `hide` and `close`
asnprintf(&str, &len, FADING_TEMPLATE_1 FADING_TEMPLATE_2, duration, duration,
1.F, 0.F);
auto fade_out1 = compile_win_script_from_string(str, output_indices);
number_of_triggers = 0;
if (opt->animations[ANIMATION_TRIGGER_CLOSE].script == NULL &&
!opt->no_fading_openclose) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_CLOSE;
}
if (opt->animations[ANIMATION_TRIGGER_HIDE].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_HIDE;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_out1,
output_indices, 0, 0)) {
scripts[number_of_scripts++] = fade_out1;
} else {
script_free(fade_out1);
}
if (!safe_isinf(duration) && !safe_isnan(duration) && duration > 0) {
scoped_charp duration_str = NULL;
dtostr(duration, &duration_str);

// Fading out to nothing, i.e. `hide` and `close`
asnprintf(&str, &len, FADING_TEMPLATE_1 FADING_TEMPLATE_2, duration_str,
duration_str, 1, 0);
auto fade_out1 = compile_win_script_from_string(str, output_indices);
number_of_triggers = 0;
if (opt->animations[ANIMATION_TRIGGER_CLOSE].script == NULL &&
!opt->no_fading_openclose) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_CLOSE;
}
if (opt->animations[ANIMATION_TRIGGER_HIDE].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_HIDE;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_out1,
output_indices, 0, 0)) {
scripts[number_of_scripts++] = fade_out1;
} else {
script_free(fade_out1);
}

// Fading for opacity change
asnprintf(&str, &len, FADING_TEMPLATE_1, duration);
auto fade_out2 = compile_win_script_from_string(str, output_indices);
number_of_triggers = 0;
if (opt->animations[ANIMATION_TRIGGER_DECREASE_OPACITY].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_DECREASE_OPACITY;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_out2,
output_indices, 0, 0)) {
scripts[number_of_scripts++] = fade_out2;
// Fading for opacity change
asnprintf(&str, &len, FADING_TEMPLATE_1, duration_str);
auto fade_out2 = compile_win_script_from_string(str, output_indices);
number_of_triggers = 0;
if (opt->animations[ANIMATION_TRIGGER_DECREASE_OPACITY].script == NULL) {
trigger[number_of_triggers++] = ANIMATION_TRIGGER_DECREASE_OPACITY;
}
if (set_animation(opt->animations, trigger, number_of_triggers, fade_out2,
output_indices, 0, 0)) {
scripts[number_of_scripts++] = fade_out2;
} else {
script_free(fade_out2);
}
} else {
script_free(fade_out2);
log_error("Invalid fade-out setting (step: %f, delta: %d), ignoring.",
opt->fade_out_step, opt->fade_delta);
}
free(str);

log_debug("Generated %d scripts for fading.", number_of_scripts);
if (number_of_scripts) {
Expand Down
24 changes: 22 additions & 2 deletions src/string_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
// Copyright (c) Yuxuan Shui <[email protected]>
#pragma once
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>

#include "compiler.h"
#include "utils.h"

#define mstrncmp(s1, s2) strncmp((s1), (s2), strlen(s1))

Expand Down Expand Up @@ -38,6 +39,24 @@ static inline int uitostr(unsigned int n, char *buf) {
return ret;
}

/// Convert a double into a string. Avoid using *printf functions to print floating points
/// directly because they are locale dependent.
static inline void dtostr(double n, char **buf) {
BUG_ON(safe_isnan(n));
BUG_ON(safe_isinf(n));
if (fabs(n) > 1e9) {
// The number is so big that it's not meaningful to keep decimal places.
asprintf(buf, "%.0f", n);
return;
}

if (n > 0) {
asprintf(buf, "%.0f.%03d", floor(n), (int)(fmod(n, 1) * 1000));
} else {
asprintf(buf, "-%.0f.%03d", floor(-n), (int)(fmod(-n, 1) * 1000));
}
}

static inline const char *skip_space_const(const char *src) {
if (!src) {
return NULL;
Expand Down Expand Up @@ -70,4 +89,5 @@ static inline bool starts_with(const char *str, const char *needle, bool ignore_

/// Similar to `asprintf`, but it reuses the allocated memory pointed to by `*strp`, and
/// reallocates it if it's not big enough.
int asnprintf(char **strp, size_t *capacity, const char *fmt, ...);
int asnprintf(char **strp, size_t *capacity, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
3 changes: 1 addition & 2 deletions src/win.c
Original file line number Diff line number Diff line change
Expand Up @@ -2245,11 +2245,10 @@ bool win_process_animation_and_state_change(struct session *ps, struct managed_w
bool will_never_render = !w->ever_damaged && w->state != WSTATE_MAPPED;
if (!ps->redirected || will_never_render) {
// This window won't be rendered, so we don't need to run the animations.
assert(w->running_animation == NULL);
bool state_changed = w->previous.state != w->state;
w->previous.state = w->state;
w->opacity = win_calc_opacity_target(ps, w);
return state_changed;
return state_changed || (w->running_animation != NULL);
}

auto win_ctx = win_script_context_prepare(ps, w);
Expand Down
29 changes: 20 additions & 9 deletions tests/run_one_test.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
#!/bin/sh
#!/bin/bash
set -xe
if [ -z $DISPLAY ]; then
exec xvfb-run -s "+extension composite" -a $0 $1 $2 $3
fi

echo "Running test $2"

# TODO keep the log file, and parse it to see if test is successful
($1 --dbus --backend dummy --log-level=debug --log-file=$PWD/log --config=$2) &
main_pid=$!
$3
picom_exe=$1
config=$2
test_script=$3

kill -INT $main_pid || true
cat log
rm log
wait $main_pid
function test_with_backend() {
backend=$1
# TODO keep the log file, and parse it to see if test is successful
($picom_exe --dbus --backend $backend --log-level=debug --log-file=$PWD/log --config=$config) &
main_pid=$!
$test_script

kill -INT $main_pid || true
cat log
rm log
wait $main_pid
}

test_with_backend dummy
test_with_backend xrender
test_with_backend glx
# test_with_backend egl

0 comments on commit 17d048c

Please sign in to comment.