diff --git a/config.conf b/config.conf index 6cbb3a20..1e55cb7f 100644 --- a/config.conf +++ b/config.conf @@ -178,6 +178,12 @@ bind=SUPER,o,toggleoverlay, bind=SUPER+SHIFT,I,restore_minimized bind=ALT,z,toggle_scratchpad +# window opacity control +bind=SUPER,equal,inc_opacity,0.1 +bind=SUPER,minus,dec_opacity,0.1 +bind=SUPER+SHIFT,o,toggle_opacity, +bind=SUPER+SHIFT,c,clear_custom_opacity, + # scroller layout bind=ALT,e,set_proportion,1.0 bind=ALT,x,switch_proportion_preset, diff --git a/src/animation/client.h b/src/animation/client.h index 849bc10e..6ad46712 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1044,10 +1044,17 @@ void client_set_focused_opacity_animation(Client *c) { return; } + float opacity = + c == selmon->sel ? c->focused_opacity : c->unfocused_opacity; + + if (c->custom_opacity > 0.0f) { + opacity = c->custom_opacity; + } + c->opacity_animation.duration = animation_duration_focus; memcpy(c->opacity_animation.target_border_color, border_color, sizeof(c->opacity_animation.target_border_color)); - c->opacity_animation.target_opacity = c->focused_opacity; + c->opacity_animation.target_opacity = opacity; c->opacity_animation.time_started = get_now_in_ms(); if (c->opacity_animation.running) { memcpy(c->opacity_animation.initial_border_color, @@ -1070,6 +1077,13 @@ void client_set_unfocused_opacity_animation(Client *c) { // Start border color animation to unfocused float *border_color = get_border_color(c); + float opacity = + c == selmon->sel ? c->focused_opacity : c->unfocused_opacity; + + if (c->custom_opacity > 0.0f) { + opacity = c->custom_opacity; + } + if (!animations) { setborder_color(c); return; @@ -1079,7 +1093,7 @@ void client_set_unfocused_opacity_animation(Client *c) { memcpy(c->opacity_animation.target_border_color, border_color, sizeof(c->opacity_animation.target_border_color)); // Start opacity animation to unfocused - c->opacity_animation.target_opacity = c->unfocused_opacity; + c->opacity_animation.target_opacity = opacity; c->opacity_animation.time_started = get_now_in_ms(); if (c->opacity_animation.running) { @@ -1103,6 +1117,13 @@ void client_set_unfocused_opacity_animation(Client *c) { bool client_apply_focus_opacity(Client *c) { // Animate focus transitions (opacity + border color) float *border_color = get_border_color(c); + float opacity = + c == selmon->sel ? c->focused_opacity : c->unfocused_opacity; + + if (c->custom_opacity > 0.0f) { + opacity = c->custom_opacity; + } + if (c->isfullscreen) { c->opacity_animation.running = false; client_set_opacity(c, 1); @@ -1122,8 +1143,6 @@ bool client_apply_focus_opacity(Client *c) { float percent = animation_fade_in && !c->nofadein ? opacity_eased_progress : 1.0; - float opacity = - c == selmon->sel ? c->focused_opacity : c->unfocused_opacity; float target_opacity = percent * (1.0 - fadein_begin_opacity) + fadein_begin_opacity; @@ -1168,16 +1187,16 @@ bool client_apply_focus_opacity(Client *c) { } } else if (c == selmon->sel) { c->opacity_animation.running = false; - c->opacity_animation.current_opacity = c->focused_opacity; + c->opacity_animation.current_opacity = opacity; memcpy(c->opacity_animation.current_border_color, border_color, sizeof(c->opacity_animation.current_border_color)); - client_set_opacity(c, c->focused_opacity); + client_set_opacity(c, opacity); } else { c->opacity_animation.running = false; - c->opacity_animation.current_opacity = c->unfocused_opacity; + c->opacity_animation.current_opacity = opacity; memcpy(c->opacity_animation.current_border_color, border_color, sizeof(c->opacity_animation.current_border_color)); - client_set_opacity(c, c->unfocused_opacity); + client_set_opacity(c, opacity); } return false; diff --git a/src/config/parse_config.h b/src/config/parse_config.h index b2535b15..c2c18881 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1083,6 +1083,16 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "scroller_stack") == 0) { func = scroller_stack; (*arg).i = parse_direction(arg_value); + } else if (strcmp(func_name, "toggle_opacity") == 0) { + func = toggle_opacity; + } else if (strcmp(func_name, "inc_opacity") == 0) { + (*arg).f = atof(arg_value); + func = inc_opacity; + } else if (strcmp(func_name, "dec_opacity") == 0) { + (*arg).f = atof(arg_value); + func = dec_opacity; + } else if (strcmp(func_name, "clear_custom_opacity") == 0) { + func = clear_custom_opacity; } else { return NULL; } diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index 22ef6123..b7e53cfc 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -69,4 +69,8 @@ int32_t setoption(const Arg *arg); int32_t disable_monitor(const Arg *arg); int32_t enable_monitor(const Arg *arg); int32_t toggle_monitor(const Arg *arg); -int32_t scroller_stack(const Arg *arg); \ No newline at end of file +int32_t scroller_stack(const Arg *arg); +int32_t toggle_opacity(const Arg *arg); +int32_t inc_opacity(const Arg *arg); +int32_t dec_opacity(const Arg *arg); +int32_t clear_custom_opacity(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 3ca79978..0d49c3da 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1672,4 +1672,64 @@ int32_t scroller_stack(const Arg *arg) { arrange(selmon, false, false); return 0; -} \ No newline at end of file +} + +int32_t toggle_opacity(const Arg *arg) { + Client *c = selmon->sel; + if (!c) + return 0; + + if (c->custom_opacity > 0.0f) { + c->custom_opacity = 0.0f; + client_set_opacity(c, c->focused_opacity); + } else { + c->custom_opacity = 1.0f; + client_set_opacity(c, 1.0f); + } + return 0; +} + +int32_t inc_opacity(const Arg *arg) { + Client *c = selmon->sel; + if (!c) + return 0; + + float value = CLAMP_FLOAT(arg->f, 0.01f, 1.0f); + + if (c->custom_opacity == 0.0f) { + c->custom_opacity = c->focused_opacity; + } + + float target = MIN(c->custom_opacity + value, 1.0f); + c->custom_opacity = target; + client_set_opacity(c, target); + return 0; +} + +int32_t dec_opacity(const Arg *arg) { + Client *c = selmon->sel; + + if (!c) + return 0; + + float value = CLAMP_FLOAT(arg->f, 0.01f, 1.0f); + + if (c->custom_opacity == 0.0f) { + c->custom_opacity = c->focused_opacity; + } + + float target = MAX(c->custom_opacity - value, 0.01f); + c->custom_opacity = target; + client_set_opacity(c, target); + return 0; +} + +int32_t clear_custom_opacity(const Arg *arg) { + Client *c = selmon->sel; + if (!c) + return 0; + + c->custom_opacity = 0.0f; + client_set_opacity(c, c->focused_opacity); + return 0; +} diff --git a/src/mango.c b/src/mango.c index 145a55a5..64b1fbac 100644 --- a/src/mango.c +++ b/src/mango.c @@ -401,6 +401,7 @@ struct Client { int32_t isunglobal; float focused_opacity; float unfocused_opacity; + float custom_opacity; char oldmonname[128]; int32_t noblur; double master_mfact_per, master_inner_per, stack_inner_per; @@ -3741,6 +3742,7 @@ void init_client_properties(Client *c) { c->fake_no_border = false; c->focused_opacity = focused_opacity; c->unfocused_opacity = unfocused_opacity; + c->custom_opacity = 0.0f; c->nofocus = 0; c->nofadein = 0; c->nofadeout = 0;