[Feature] Dim inactive windows (#66)

This commit is contained in:
Erik Reider 2022-12-07 06:10:11 +01:00 committed by GitHub
parent e82e4de37f
commit 988fb24710
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 156 additions and 9 deletions

View file

@ -5,6 +5,7 @@
Sway is an incredible window manager, and certainly one of the most well established wayland window managers. However, it is restricted to only include the functionality that existed in i3. This fork ditches the simple wlr_renderer, and replaces it with our fx_renderer, capable of rendering with fancy GLES2 effects. This, along with a couple of minor changes, expands sway's featureset to include the following: Sway is an incredible window manager, and certainly one of the most well established wayland window managers. However, it is restricted to only include the functionality that existed in i3. This fork ditches the simple wlr_renderer, and replaces it with our fx_renderer, capable of rendering with fancy GLES2 effects. This, along with a couple of minor changes, expands sway's featureset to include the following:
+ **Anti-aliased rounded corners, borders, and titlebars** + **Anti-aliased rounded corners, borders, and titlebars**
+ **Dim unfocused windows**
+ **Per application saturation control**: Allows the user to set the saturation (Digital Vibrance) for specific applications. Great for some FPS games! + **Per application saturation control**: Allows the user to set the saturation (Digital Vibrance) for specific applications. Great for some FPS games!
+ **Scratchpad treated as minimize**: Allows docks, or panels with a taskbar, to correctly interpret minimize / unminimize requests ([thanks to LCBCrion](https://github.com/swaywm/sway/issues/6457)) + **Scratchpad treated as minimize**: Allows docks, or panels with a taskbar, to correctly interpret minimize / unminimize requests ([thanks to LCBCrion](https://github.com/swaywm/sway/issues/6457))
+ **Add a nix flake to the repo**: Allows nixos users to easily contribute to and test this project + **Add a nix flake to the repo**: Allows nixos users to easily contribute to and test this project
@ -13,6 +14,10 @@ Sway is an incredible window manager, and certainly one of the most well establi
+ Corner radius: `corner_radius <val>` + Corner radius: `corner_radius <val>`
+ Application saturation: `for_window [CRITERIA HERE] saturation <set|plus|minus> <val 0.0 <-> 2.0>` + Application saturation: `for_window [CRITERIA HERE] saturation <set|plus|minus> <val 0.0 <-> 2.0>`
+ Dim unfocused windows:
- `dim_inactive <float value 0.0 - 1.0>`
- `dim_inactive_colors.unfocused <hex color> ex, #000000FF`
- `dim_inactive_colors.urgent <hex color> ex, #900000FF`
## Roadmap ## Roadmap

View file

@ -24,6 +24,11 @@ set $menu dmenu_path | dmenu | xargs swaymsg exec --
# window corner radius in px # window corner radius in px
corner_radius 10 corner_radius 10
# inactive window fade amount. 0.0 = no dimming, 1.0 = fully dimmed
dim_inactive 0.0
dim_inactive_colors.unfocused #000000FF
dim_inactive_colors.urgent #900000FF
### Output configuration ### Output configuration
# #
# Default wallpaper (more resolutions are available in @datadir@/backgrounds/sway/) # Default wallpaper (more resolutions are available in @datadir@/backgrounds/sway/)

View file

@ -123,6 +123,9 @@ sway_cmd cmd_create_output;
sway_cmd cmd_default_border; sway_cmd cmd_default_border;
sway_cmd cmd_default_floating_border; sway_cmd cmd_default_floating_border;
sway_cmd cmd_default_orientation; sway_cmd cmd_default_orientation;
sway_cmd cmd_dim_inactive;
sway_cmd cmd_dim_inactive_colors_unfocused;
sway_cmd cmd_dim_inactive_colors_urgent;
sway_cmd cmd_exec; sway_cmd cmd_exec;
sway_cmd cmd_exec_always; sway_cmd cmd_exec_always;
sway_cmd cmd_exit; sway_cmd cmd_exit;

View file

@ -468,6 +468,12 @@ enum xwayland_mode {
struct sway_config { struct sway_config {
// SwayFX config options // SwayFX config options
int corner_radius; int corner_radius;
float dim_inactive;
// dim_inactive colors
struct {
float unfocused[4];
float urgent[4];
} dim_inactive_colors;
char *swaynag_command; char *swaynag_command;
struct swaynag_instance swaynag_config_errors; struct swaynag_instance swaynag_config_errors;

View file

@ -11,6 +11,8 @@ struct decoration_data {
float alpha; float alpha;
float saturation; float saturation;
int corner_radius; int corner_radius;
float dim;
float* dim_color;
bool has_titlebar; bool has_titlebar;
}; };
@ -25,6 +27,8 @@ struct gles2_tex_shader {
GLint position; GLint position;
GLint radius; GLint radius;
GLint saturation; GLint saturation;
GLint dim;
GLint dim_color;
GLint has_titlebar; GLint has_titlebar;
}; };

View file

@ -58,6 +58,9 @@ static const struct cmd_handler handlers[] = {
{ "corner_radius", cmd_corner_radius }, { "corner_radius", cmd_corner_radius },
{ "default_border", cmd_default_border }, { "default_border", cmd_default_border },
{ "default_floating_border", cmd_default_floating_border }, { "default_floating_border", cmd_default_floating_border },
{ "dim_inactive", cmd_dim_inactive },
{ "dim_inactive_colors.unfocused", cmd_dim_inactive_colors_unfocused },
{ "dim_inactive_colors.urgent", cmd_dim_inactive_colors_urgent },
{ "exec", cmd_exec }, { "exec", cmd_exec },
{ "exec_always", cmd_exec_always }, { "exec_always", cmd_exec_always },
{ "floating_maximum_size", cmd_floating_maximum_size }, { "floating_maximum_size", cmd_floating_maximum_size },

View file

@ -0,0 +1,29 @@
#include <string.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "log.h"
#include "sway/output.h"
struct cmd_results *cmd_dim_inactive(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "dim_inactive", EXPECTED_EQUAL_TO, 1))) {
return error;
}
char *err;
float val = strtof(argv[0], &err);
if (*err || val < 0.0f || val > 1.0f) {
return cmd_results_new(CMD_INVALID, "dim_inactive float invalid");
}
config->dim_inactive = val;
if (config->active) {
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
output_damage_whole(output);
}
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -0,0 +1,40 @@
#include "log.h"
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
#include "sway/tree/container.h"
#include "util.h"
static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
float config_option[4]) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, cmd_name, EXPECTED_AT_LEAST, 1))) {
return error;
}
uint32_t color;
if (!parse_color(argv[0], &color)) {
return cmd_results_new(CMD_INVALID, "Invalid %s color %s",
cmd_name, argv[0]);
}
color_to_rgba(config_option, color);
if (config->active) {
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
output_damage_whole(output);
}
}
return cmd_results_new(CMD_SUCCESS, NULL);
}
struct cmd_results *cmd_dim_inactive_colors_unfocused(int argc, char **argv) {
return handle_command(argc, argv, "dim_inactive_colors.unfocused",
config->dim_inactive_colors.unfocused);
}
struct cmd_results *cmd_dim_inactive_colors_urgent(int argc, char **argv) {
return handle_command(argc, argv, "dim_inactive_colors.urgent",
config->dim_inactive_colors.urgent);
}

View file

@ -327,6 +327,9 @@ static void config_defaults(struct sway_config *config) {
// SwayFX defaults // SwayFX defaults
config->corner_radius = 0; config->corner_radius = 0;
config->dim_inactive = 1.0f;
color_to_rgba(config->dim_inactive_colors.unfocused, 0x000000FF);
color_to_rgba(config->dim_inactive_colors.urgent, 0x900000FF);
// The keysym to keycode translation // The keysym to keycode translation
struct xkb_rule_names rules = {0}; struct xkb_rule_names rules = {0};

View file

@ -95,6 +95,8 @@ bool init_frag_shader(struct gles2_tex_shader *shader, GLuint prog) {
shader->proj = glGetUniformLocation(prog, "proj"); shader->proj = glGetUniformLocation(prog, "proj");
shader->tex = glGetUniformLocation(prog, "tex"); shader->tex = glGetUniformLocation(prog, "tex");
shader->alpha = glGetUniformLocation(prog, "alpha"); shader->alpha = glGetUniformLocation(prog, "alpha");
shader->dim = glGetUniformLocation(prog, "dim");
shader->dim_color = glGetUniformLocation(prog, "dim_color");
shader->pos_attrib = glGetAttribLocation(prog, "pos"); shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->tex_attrib = glGetAttribLocation(prog, "texcoord"); shader->tex_attrib = glGetAttribLocation(prog, "texcoord");
shader->size = glGetUniformLocation(prog, "size"); shader->size = glGetUniformLocation(prog, "size");
@ -345,11 +347,15 @@ bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct wlr_t
glUseProgram(shader->program); glUseProgram(shader->program);
float* dim_color = deco_data.dim_color;
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix);
glUniform1i(shader->tex, 0); glUniform1i(shader->tex, 0);
glUniform2f(shader->size, dst_box->width, dst_box->height); glUniform2f(shader->size, dst_box->width, dst_box->height);
glUniform2f(shader->position, dst_box->x, dst_box->y); glUniform2f(shader->position, dst_box->x, dst_box->y);
glUniform1f(shader->alpha, deco_data.alpha); glUniform1f(shader->alpha, deco_data.alpha);
glUniform1f(shader->dim, deco_data.dim);
glUniform4f(shader->dim_color, dim_color[0], dim_color[1], dim_color[2], dim_color[3]);
glUniform1f(shader->has_titlebar, deco_data.has_titlebar); glUniform1f(shader->has_titlebar, deco_data.has_titlebar);
glUniform1f(shader->saturation, deco_data.saturation); glUniform1f(shader->saturation, deco_data.saturation);
glUniform1f(shader->radius, deco_data.corner_radius); glUniform1f(shader->radius, deco_data.corner_radius);

View file

@ -39,6 +39,8 @@ struct render_data {
struct decoration_data get_undecorated_decoration_data() { struct decoration_data get_undecorated_decoration_data() {
return (struct decoration_data) { return (struct decoration_data) {
.alpha = 1.0f, .alpha = 1.0f,
.dim = 0.0f,
.dim_color = config->dim_inactive_colors.unfocused,
.corner_radius = 0, .corner_radius = 0,
.saturation = 1.0f, .saturation = 1.0f,
.has_titlebar = false, .has_titlebar = false,
@ -945,6 +947,10 @@ static void render_containers_linear(struct sway_output *output,
bool has_titlebar = state->border == B_NORMAL; bool has_titlebar = state->border == B_NORMAL;
struct decoration_data deco_data = { struct decoration_data deco_data = {
.alpha = child->alpha, .alpha = child->alpha,
.dim_color = view_is_urgent(view)
? config->dim_inactive_colors.urgent
: config->dim_inactive_colors.unfocused,
.dim = child->current.focused ? 0.0f: config->dim_inactive,
// no corner radius if smart gaps are on and only visible view // no corner radius if smart gaps are on and only visible view
.corner_radius = config->smart_gaps == SMART_GAPS_ON && .corner_radius = config->smart_gaps == SMART_GAPS_ON &&
view_ancestor_is_only_visible(view) ? 0 : child->corner_radius, view_ancestor_is_only_visible(view) ? 0 : child->corner_radius,
@ -1038,6 +1044,10 @@ static void render_containers_tabbed(struct sway_output *output,
if (current->view) { if (current->view) {
struct decoration_data deco_data = { struct decoration_data deco_data = {
.alpha = current->alpha, .alpha = current->alpha,
.dim_color = view_is_urgent(current->view)
? config->dim_inactive_colors.urgent
: config->dim_inactive_colors.unfocused,
.dim = current->current.focused ? 0.0f: config->dim_inactive,
.corner_radius = current->corner_radius, .corner_radius = current->corner_radius,
.saturation = current->saturation, .saturation = current->saturation,
.has_titlebar = true, .has_titlebar = true,
@ -1107,6 +1117,10 @@ static void render_containers_stacked(struct sway_output *output,
if (current->view) { if (current->view) {
struct decoration_data deco_data = { struct decoration_data deco_data = {
.alpha = current->alpha, .alpha = current->alpha,
.dim_color = view_is_urgent(current->view)
? config->dim_inactive_colors.urgent
: config->dim_inactive_colors.unfocused,
.dim = current->current.focused ? 0.0f: config->dim_inactive,
.saturation = current->saturation, .saturation = current->saturation,
.corner_radius = current->corner_radius, .corner_radius = current->corner_radius,
.has_titlebar = true, .has_titlebar = true,
@ -1203,6 +1217,10 @@ static void render_floating_container(struct sway_output *soutput,
bool has_titlebar = state->border == B_NORMAL; bool has_titlebar = state->border == B_NORMAL;
struct decoration_data deco_data = { struct decoration_data deco_data = {
.alpha = con->alpha, .alpha = con->alpha,
.dim_color = view_is_urgent(view)
? config->dim_inactive_colors.urgent
: config->dim_inactive_colors.unfocused,
.dim = con->current.focused ? 0.0f: config->dim_inactive,
.saturation = con->saturation, .saturation = con->saturation,
.corner_radius = con->corner_radius, .corner_radius = con->corner_radius,
.has_titlebar = has_titlebar, .has_titlebar = has_titlebar,
@ -1355,6 +1373,10 @@ void output_render(struct sway_output *output, struct timespec *when,
if (focus && focus->view) { if (focus && focus->view) {
struct decoration_data deco_data = { struct decoration_data deco_data = {
.alpha = focus->alpha, .alpha = focus->alpha,
.dim_color = view_is_urgent(focus->view)
? config->dim_inactive_colors.urgent
: config->dim_inactive_colors.unfocused,
.dim = focus->current.focused ? 0.0f: config->dim_inactive,
.corner_radius = focus->corner_radius, .corner_radius = focus->corner_radius,
.saturation = focus->saturation, .saturation = focus->saturation,
.has_titlebar = focus->current.border == B_NORMAL, .has_titlebar = focus->current.border == B_NORMAL,

View file

@ -4,6 +4,8 @@ precision mediump float;
varying vec2 v_texcoord; varying vec2 v_texcoord;
uniform samplerExternalOES texture0; uniform samplerExternalOES texture0;
uniform float alpha; uniform float alpha;
uniform float dim;
uniform vec4 dim_color;
uniform vec2 size; uniform vec2 size;
uniform vec2 position; uniform vec2 position;
@ -13,15 +15,16 @@ uniform float saturation;
const vec3 saturation_weight = vec3(0.2125, 0.7154, 0.0721); const vec3 saturation_weight = vec3(0.2125, 0.7154, 0.0721);
void main() { void main() {
vec4 color = texture2D(texture0, v_texcoord);
// Saturation // Saturation
if (saturation != 1.0) { if (saturation != 1.0) {
vec4 pixColor = texture2D(texture0, v_texcoord); vec4 pixColor = texture2D(texture0, v_texcoord);
vec3 irgb = pixColor.rgb; vec3 irgb = pixColor.rgb;
vec3 target = vec3(dot(irgb, saturation_weight)); vec3 target = vec3(dot(irgb, saturation_weight));
gl_FragColor = vec4(mix(target, irgb, saturation), pixColor.a) * alpha; color = vec4(mix(target, irgb, saturation), pixColor.a);
} else {
gl_FragColor = texture2D(texture0, v_texcoord) * alpha;
} }
// Dimming
gl_FragColor = mix(color, dim_color, dim) * alpha;
if (!has_titlebar || gl_FragCoord.y - position.y > radius) { if (!has_titlebar || gl_FragCoord.y - position.y > radius) {
vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy);

View file

@ -2,6 +2,8 @@ precision mediump float;
varying vec2 v_texcoord; varying vec2 v_texcoord;
uniform sampler2D tex; uniform sampler2D tex;
uniform float alpha; uniform float alpha;
uniform float dim;
uniform vec4 dim_color;
uniform vec2 size; uniform vec2 size;
uniform vec2 position; uniform vec2 position;
@ -11,15 +13,16 @@ uniform float saturation;
const vec3 saturation_weight = vec3(0.2125, 0.7154, 0.0721); const vec3 saturation_weight = vec3(0.2125, 0.7154, 0.0721);
void main() { void main() {
vec4 color = texture2D(tex, v_texcoord);
// Saturation // Saturation
if (saturation != 1.0) { if (saturation != 1.0) {
vec4 pixColor = texture2D(tex, v_texcoord); vec4 pixColor = texture2D(tex, v_texcoord);
vec3 irgb = pixColor.rgb; vec3 irgb = pixColor.rgb;
vec3 target = vec3(dot(irgb, saturation_weight)); vec3 target = vec3(dot(irgb, saturation_weight));
gl_FragColor = vec4(mix(target, irgb, saturation), pixColor.a) * alpha; color = vec4(mix(target, irgb, saturation), pixColor.a);
} else {
gl_FragColor = texture2D(tex, v_texcoord) * alpha;
} }
// Dimming
gl_FragColor = mix(color, dim_color, dim) * alpha;
if (!has_titlebar || gl_FragCoord.y - position.y > radius) { if (!has_titlebar || gl_FragCoord.y - position.y > radius) {
vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy);

View file

@ -2,6 +2,8 @@ precision mediump float;
varying vec2 v_texcoord; varying vec2 v_texcoord;
uniform sampler2D tex; uniform sampler2D tex;
uniform float alpha; uniform float alpha;
uniform float dim;
uniform vec4 dim_color;
uniform vec2 size; uniform vec2 size;
uniform vec2 position; uniform vec2 position;
@ -11,14 +13,15 @@ uniform float saturation;
const vec3 saturation_weight = vec3(0.2125, 0.7154, 0.0721); const vec3 saturation_weight = vec3(0.2125, 0.7154, 0.0721);
void main() { void main() {
vec4 color = vec4(texture2D(tex, v_texcoord).rgb, 1.0);
// Saturation // Saturation
if (saturation != 1.0) { if (saturation != 1.0) {
vec3 irgb = texture2D(tex, v_texcoord).rgb; vec3 irgb = texture2D(tex, v_texcoord).rgb;
vec3 target = vec3(dot(irgb, saturation_weight)); vec3 target = vec3(dot(irgb, saturation_weight));
gl_FragColor = vec4(mix(target, irgb, saturation), 1.0) * alpha; color = vec4(mix(target, irgb, saturation), 1.0);
} else {
gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;
} }
// Dimming
gl_FragColor = mix(color, dim_color, dim) * alpha;
if (!has_titlebar || gl_FragCoord.y - position.y > radius) { if (!has_titlebar || gl_FragCoord.y - position.y > radius) {
vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy); vec2 corner_distance = min(gl_FragCoord.xy - position, size + position - gl_FragCoord.xy);

View file

@ -51,6 +51,8 @@ sway_sources = files(
'commands/default_border.c', 'commands/default_border.c',
'commands/default_floating_border.c', 'commands/default_floating_border.c',
'commands/default_orientation.c', 'commands/default_orientation.c',
'commands/dim_inactive.c',
'commands/dim_inactive_colors.c',
'commands/exit.c', 'commands/exit.c',
'commands/exec.c', 'commands/exec.c',
'commands/exec_always.c', 'commands/exec_always.c',

View file

@ -588,6 +588,16 @@ The default colors are:
*corner_radius* <radius> *corner_radius* <radius>
Set corner radius for new windows. Set corner radius for new windows.
*dim_inactive* <value>
Adjusts the dimming of inactive windows between 0.0 (no dimming) and 1.0
(fully dimmed) while 0.0 is the default value.
*dim_inactive_colors.unfocused* <hex color>
The color to dim inactive windows with. Example color: #000000FF
*dim_inactive_colors.urgent* <hex color>
The color to dim inactive urgent windows with. Example color: #900000FF
*default_border* normal|none|pixel [<n>] *default_border* normal|none|pixel [<n>]
Set default border style for new tiled windows. Set default border style for new tiled windows.