Skip to content

Commit

Permalink
#148 make frame rate configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
koekeishiya committed Dec 28, 2022
1 parent 35ac830 commit 76f5230
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Fixed issue with window warping across displays with only a single window tiled at both displays [#1577](https://github.com/koekeishiya/yabai/issues/1577)
- Fixed issue preventing window split from being toggled for windwos on an inactive space/display [#1557](https://github.com/koekeishiya/yabai/issues/1557)
- Make window zoom persistence configurable (*config window_zoom_persist*) [#1481](https://github.com/koekeishiya/yabai/issues/1481)
- Make frame rate of window animations configurable (*config window_animation_frame_rate*) [#148](https://github.com/koekeishiya/yabai/issues/148)

## [5.0.2] - 2022-12-16
### Changed
Expand Down
7 changes: 7 additions & 0 deletions doc/yabai.1
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ Requires Screen Recording permissions.
System Integrity Protection must be partially disabled.
.RE
.sp
\fBwindow_animation_frame_rate\fP [\fI<integer number>\fP]
.RS 4
Frame rate (expressed in frames per second) of window frame animation.
.br
This setting does nothing if \fBwindow_animation_duration\fP is set to 0.0.
.RE
.sp
\fBactive_window_opacity\fP [\fI<FLOAT_SEL>\fP]
.RS 4
Opacity of the focused window.
Expand Down
4 changes: 4 additions & 0 deletions doc/yabai.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ Global Settings
Requires Screen Recording permissions. +
System Integrity Protection must be partially disabled.

*window_animation_frame_rate* ['<integer number>']::
Frame rate (expressed in frames per second) of window frame animation. +
This setting does nothing if *window_animation_duration* is set to 0.0.

*active_window_opacity* ['<FLOAT_SEL>']::
Opacity of the focused window. +
System Integrity Protection must be partially disabled.
Expand Down
1 change: 1 addition & 0 deletions src/manifest.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <Carbon/Carbon.h>
#include <Cocoa/Cocoa.h>
#include <objc/objc-runtime.h>
#include <mach/mach_time.h>

#include <stdio.h>
#include <stdlib.h>
Expand Down
10 changes: 10 additions & 0 deletions src/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extern bool g_verbose;
#define COMMAND_CONFIG_OPACITY "window_opacity"
#define COMMAND_CONFIG_OPACITY_DURATION "window_opacity_duration"
#define COMMAND_CONFIG_ANIMATION_DURATION "window_animation_duration"
#define COMMAND_CONFIG_ANIMATION_FRAME_RATE "window_animation_frame_rate"
#define COMMAND_CONFIG_BORDER "window_border"
#define COMMAND_CONFIG_BORDER_HIDPI "window_border_hidpi"
#define COMMAND_CONFIG_BORDER_BLUR "window_border_blur"
Expand Down Expand Up @@ -1170,6 +1171,15 @@ static void handle_domain_config(FILE *rsp, struct token domain, char *message)
} else {
daemon_fail(rsp, "unknown value '%.*s' given to command '%.*s' for domain '%.*s'\n", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);
}
} else if (token_equals(command, COMMAND_CONFIG_ANIMATION_FRAME_RATE)) {
struct token_value value = token_to_value(get_token(&message), false);
if (value.type == TOKEN_TYPE_INVALID) {
fprintf(rsp, "%d\n", g_window_manager.window_animation_frame_rate);
} else if (value.type == TOKEN_TYPE_INT && value.int_value) {
g_window_manager.window_animation_frame_rate = value.int_value;
} else {
daemon_fail(rsp, "unknown value '%.*s' given to command '%.*s' for domain '%.*s'\n", value.token.length, value.token.text, command.length, command.text, domain.length, domain.text);
}
} else if (token_equals(command, COMMAND_CONFIG_BORDER)) {
struct token value = get_token(&message);
if (!token_is_valid(value)) {
Expand Down
74 changes: 53 additions & 21 deletions src/misc/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,64 @@ static const char *layer_str[] =
[LAYER_ABOVE] = "above"
};

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
static inline uint64_t get_wall_clock(void)
{
uint64_t absolute = mach_absolute_time();
Nanoseconds result = AbsoluteToNanoseconds(*(AbsoluteTime *) &absolute);
return *(uint64_t *) &result;
}
#pragma clang diagnostic pop

static inline float get_seconds_elapsed(uint64_t start, uint64_t end)
{
float result = ((float)(end - start) / 1000.0f) / 1000000.0f;
return result;
}

static inline float ease_out_cubic(float t)
{
return 1.0f - powf(1.0f - t, 3.0f);
}

#define ANIMATE(animation_connection, animation_duration, easing_function, code_block) \
{ \
int frame_duration = 4; \
int total_duration = (int)(animation_duration * 1000.0f); \
int frame_count = (int)(((float) total_duration / (float) frame_duration) + 1.0f); \
\
for (int frame_index = 1; frame_index <= frame_count; ++frame_index) { \
float t = (float) frame_index / (float) frame_count; \
if (t < 0.0f) t = 0.0f; \
if (t > 1.0f) t = 1.0f; \
\
float mt = easing_function(t); \
CFTypeRef transaction = SLSTransactionCreate(animation_connection); \
\
code_block \
\
SLSTransactionCommit(transaction, 0); \
CFRelease(transaction); \
\
usleep(frame_duration*1000); \
} \
#define ANIMATE_DELAY(current_frame_duration) \
while (frame_elapsed < current_frame_duration) { \
uint32_t sleep_ms = (uint32_t)(1000.0f * (current_frame_duration - frame_elapsed)); \
usleep(sleep_ms * 700.0f); \
frame_elapsed = get_seconds_elapsed(last_counter, get_wall_clock()); \
}

#define ANIMATE(connection, frame_rate, duration, easing_function, code_block) \
{ \
float frame_duration = 1.0f / (float)frame_rate; \
int frame_count = (int)((duration / frame_duration) + 1.0f); \
uint64_t last_counter = get_wall_clock(); \
\
for (int frame_index = 1; frame_index <= frame_count; ++frame_index) { \
float t = (float) frame_index / (float) frame_count; \
if (t < 0.0f) t = 0.0f; \
if (t > 1.0f) t = 1.0f; \
\
float mt = easing_function(t); \
CFTypeRef transaction = SLSTransactionCreate(connection); \
\
code_block \
\
SLSTransactionCommit(transaction, 0); \
CFRelease(transaction); \
\
float frame_elapsed = get_seconds_elapsed(last_counter, get_wall_clock()); \
if (frame_elapsed < frame_duration) { \
ANIMATE_DELAY(frame_duration); \
} else { \
int frame_skip = (int)((frame_elapsed / frame_duration) + 0.5f); \
frame_index += frame_skip; \
ANIMATE_DELAY(frame_duration * frame_skip); \
} \
\
last_counter = get_wall_clock(); \
} \
}

static inline bool socket_open(int *sockfd)
Expand Down
1 change: 1 addition & 0 deletions src/view.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct window_animation_context
{
int animation_connection;
float animation_duration;
int animation_frame_rate;
struct window_animation *animation_list;
};

Expand Down
4 changes: 3 additions & 1 deletion src/window_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ void *window_manager_animate_window_list_thread_proc(void *data)
struct window_animation_context *context = data;
int animation_count = buf_len(context->animation_list);

ANIMATE(context->animation_connection, context->animation_duration, ease_out_cubic, {
ANIMATE(context->animation_connection, context->animation_frame_rate, context->animation_duration, ease_out_cubic, {
for (int i = 0; i < animation_count; ++i) {
if (context->animation_list[i].skip) continue;

Expand Down Expand Up @@ -600,6 +600,7 @@ void window_manager_animate_window_list_async(struct window_capture *window_list

SLSNewConnection(0, &context->animation_connection);
context->animation_duration = g_window_manager.window_animation_duration;
context->animation_frame_rate = g_window_manager.window_animation_frame_rate;
context->animation_list = NULL;

for (int i = 0; i < window_count; ++i) {
Expand Down Expand Up @@ -2286,6 +2287,7 @@ void window_manager_init(struct window_manager *wm)
wm->normal_window_opacity = 1.0f;
wm->window_opacity_duration = 0.0f;
wm->window_animation_duration = 0.0f;
wm->window_animation_frame_rate = 120;
wm->insert_feedback_windows = NULL;
wm->insert_feedback_color = rgba_color_from_hex(0xffd75f5f);
wm->active_border_color = rgba_color_from_hex(0xff775759);
Expand Down
1 change: 1 addition & 0 deletions src/window_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ struct window_manager
float normal_window_opacity;
float window_opacity_duration;
float window_animation_duration;
int window_animation_frame_rate;
uint32_t *insert_feedback_windows;
float border_resolution;
bool border_blur;
Expand Down

0 comments on commit 76f5230

Please sign in to comment.