From 678aee73e58a99321a25e8e0ffaaa05eee46b9ac Mon Sep 17 00:00:00 2001 From: topisani Date: Sat, 15 Jun 2019 11:10:24 +0200 Subject: [PATCH] Initial implementation of configurable GLESv2 drop shadows --- include/sway/commands.h | 4 + include/sway/config.h | 15 ++ include/sway/output.h | 2 + meson.build | 3 + meson_options.txt | 1 + sway/commands.c | 10 +- sway/commands/client.c | 1 + sway/commands/shadows.c | 91 ++++++++++++ sway/config.c | 16 +++ sway/desktop/render.c | 307 +++++++++++++++++++++++++++++++++++++++- sway/ipc-json.c | 5 + sway/meson.build | 1 + sway/tree/output.c | 2 + 13 files changed, 453 insertions(+), 5 deletions(-) create mode 100644 sway/commands/shadows.c diff --git a/include/sway/commands.h b/include/sway/commands.h index e0cd94d16..5174e9102 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -190,6 +190,10 @@ sway_cmd cmd_workspace; sway_cmd cmd_workspace_layout; sway_cmd cmd_ws_auto_back_and_forth; sway_cmd cmd_xwayland; +sway_cmd cmd_shadows_focused; +sway_cmd cmd_shadows_focused_inactive; +sway_cmd cmd_shadows_unfocused; +sway_cmd cmd_shadows_urgent; sway_cmd bar_cmd_bindcode; sway_cmd bar_cmd_binding_mode_indicator; diff --git a/include/sway/config.h b/include/sway/config.h index 9736a6650..1c27b05da 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -317,6 +317,12 @@ struct border_colors { float child_border[4]; }; +struct shadow_config { + int offset; + int radius; + float color[4]; +}; + enum edge_border_types { E_NONE, /**< Don't hide edge borders */ E_VERTICAL, /**< hide vertical edge borders */ @@ -504,6 +510,15 @@ struct sway_config { float background[4]; } border_colors; +#if HAVE_SHADOWS + struct { + struct shadow_config focused; + struct shadow_config focused_inactive; + struct shadow_config unfocused; + struct shadow_config urgent; + } shadow_config; +#endif + // floating view int32_t floating_maximum_width; int32_t floating_maximum_height; diff --git a/include/sway/output.h b/include/sway/output.h index 3d430ea26..5959d8b3f 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -101,6 +101,8 @@ struct sway_workspace *output_get_active_workspace(struct sway_output *output); void output_render(struct sway_output *output, struct timespec *when, pixman_region32_t *damage); +void output_init_shadow_shader(); + void output_surface_for_each_surface(struct sway_output *output, struct wlr_surface *surface, double ox, double oy, sway_surface_iterator_func_t iterator, void *user_data); diff --git a/meson.build b/meson.build index f657f874e..15841c243 100644 --- a/meson.build +++ b/meson.build @@ -87,6 +87,7 @@ if get_option('tray').enabled() and not tray_deps_found endif have_tray = (not get_option('tray').disabled()) and tray_deps_found +have_shadows = (not get_option('shadows').disabled()) conf_data = configuration_data() conf_data.set10('HAVE_XWAYLAND', have_xwayland) @@ -94,6 +95,7 @@ conf_data.set10('HAVE_GDK_PIXBUF', gdk_pixbuf.found()) conf_data.set10('HAVE_SYSTEMD', systemd.found()) conf_data.set10('HAVE_ELOGIND', elogind.found()) conf_data.set10('HAVE_TRAY', have_tray) +conf_data.set10('HAVE_SHADOWS', have_shadows) scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages')) if scdoc.found() @@ -244,6 +246,7 @@ status = [ 'elogind: @0@'.format(elogind.found()), 'tray: @0@'.format(have_tray), 'man-pages: @0@'.format(scdoc.found()), + 'shadows: @0@'.format(have_shadows), '', ] message('\n'.join(status)) diff --git a/meson_options.txt b/meson_options.txt index d3667acfd..1ff4cbeed 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,3 +6,4 @@ option('xwayland', type: 'feature', value: 'auto', description: 'Enable support option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray') option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybg') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') +option('shadows', type: 'feature', value: 'auto', description: 'Enable GLES2 drop shadow support') diff --git a/sway/commands.c b/sway/commands.c index a670f8133..38357faea 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -57,8 +57,8 @@ static struct cmd_handler handlers[] = { { "client.urgent", cmd_client_urgent }, { "default_border", cmd_default_border }, { "default_floating_border", cmd_default_floating_border }, - { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, + { "exec", cmd_exec }, { "floating_maximum_size", cmd_floating_maximum_size }, { "floating_minimum_size", cmd_floating_minimum_size }, { "floating_modifier", cmd_floating_modifier }, @@ -67,9 +67,9 @@ static struct cmd_handler handlers[] = { { "focus_on_window_activation", cmd_focus_on_window_activation }, { "focus_wrapping", cmd_focus_wrapping }, { "font", cmd_font }, - { "for_window", cmd_for_window }, { "force_display_urgency_hint", cmd_force_display_urgency_hint }, { "force_focus_wrapping", cmd_force_focus_wrapping }, + { "for_window", cmd_for_window }, { "fullscreen", cmd_fullscreen }, { "gaps", cmd_gaps }, { "hide_edge_borders", cmd_hide_edge_borders }, @@ -84,6 +84,10 @@ static struct cmd_handler handlers[] = { { "popup_during_fullscreen", cmd_popup_during_fullscreen }, { "seat", cmd_seat }, { "set", cmd_set }, + { "shadows.focused", cmd_shadows_focused}, + { "shadows.focused_inactive", cmd_shadows_focused_inactive}, + { "shadows.unfocused", cmd_shadows_unfocused}, + { "shadows.urgent", cmd_shadows_urgent}, { "show_marks", cmd_show_marks }, { "smart_borders", cmd_smart_borders }, { "smart_gaps", cmd_smart_gaps }, @@ -95,8 +99,8 @@ static struct cmd_handler handlers[] = { { "unbindcode", cmd_unbindcode }, { "unbindswitch", cmd_unbindswitch }, { "unbindsym", cmd_unbindsym }, - { "workspace", cmd_workspace }, { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, + { "workspace", cmd_workspace }, }; /* Config-time only commands. Keep alphabetized */ diff --git a/sway/commands/client.c b/sway/commands/client.c index f5c7d90fb..543954a71 100644 --- a/sway/commands/client.c +++ b/sway/commands/client.c @@ -117,3 +117,4 @@ struct cmd_results *cmd_client_noop(int argc, char **argv) { sway_log(SWAY_INFO, "Warning: %s is ignored by sway", argv[-1]); return cmd_results_new(CMD_SUCCESS, NULL); } + diff --git a/sway/commands/shadows.c b/sway/commands/shadows.c new file mode 100644 index 000000000..2c6f42011 --- /dev/null +++ b/sway/commands/shadows.c @@ -0,0 +1,91 @@ +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/output.h" +#include "sway/tree/container.h" + +/** + * Parse the hex string into an integer. + */ +static bool parse_color_int(char *hexstring, uint32_t *dest) { + if (hexstring[0] != '#') { + return false; + } + + if (strlen(hexstring) != 7 && strlen(hexstring) != 9) { + return false; + } + + ++hexstring; + char *end; + uint32_t decimal = strtol(hexstring, &end, 16); + + if (*end != '\0') { + return false; + } + + if (strlen(hexstring) == 6) { + // Add alpha + decimal = (decimal << 8) | 0xff; + } + + *dest = decimal; + return true; +} + +/** + * Parse the hex string into a float value. + */ +static bool parse_color_float(char *hexstring, float dest[static 4]) { + uint32_t decimal; + if (!parse_color_int(hexstring, &decimal)) { + return false; + } + dest[0] = ((decimal >> 24) & 0xff) / 255.0; + dest[1] = ((decimal >> 16) & 0xff) / 255.0; + dest[2] = ((decimal >> 8) & 0xff) / 255.0; + dest[3] = (decimal & 0xff) / 255.0; + return true; +} + + +static struct cmd_results *handle_shadow_cmd(int argc, char **argv, struct shadow_config* class, const char* cmd_name) { + + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 3))) { + return error; + } + + class->radius = atoi(argv[0]); + class->offset = atoi(argv[1]); + + if (!parse_color_float(argv[2], class->color)) { + return cmd_results_new(CMD_INVALID, + "Unable to parse shadow color '%s'", argv[0]); + } + + 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_shadows_focused(int argc, char **argv) { + return handle_shadow_cmd(argc, argv, &config->shadow_config.focused, "shadows.focused"); +} + +struct cmd_results *cmd_shadows_focused_inactive(int argc, char **argv) { + return handle_shadow_cmd(argc, argv, &config->shadow_config.focused_inactive, "shadows.focused_inactive"); +} + +struct cmd_results *cmd_shadows_unfocused(int argc, char **argv) { + return handle_shadow_cmd(argc, argv, &config->shadow_config.unfocused, "shadows.unfocused"); +} + +struct cmd_results *cmd_shadows_urgent(int argc, char **argv) { + return handle_shadow_cmd(argc, argv, &config->shadow_config.urgent, "shadows.urgent"); +} diff --git a/sway/config.c b/sway/config.c index 4e64bd3a3..e18a47d55 100644 --- a/sway/config.c +++ b/sway/config.c @@ -331,6 +331,22 @@ static void config_defaults(struct sway_config *config) { set_color(config->border_colors.background, 0xFFFFFF); + config->shadow_config.focused.radius = 25; + config->shadow_config.focused.offset = 5; + set_color(config->shadow_config.focused.color, 0x203040); + + config->shadow_config.focused_inactive.radius = 25; + config->shadow_config.focused_inactive.offset = 5; + set_color(config->shadow_config.focused_inactive.color, 0x404040); + + config->shadow_config.unfocused.radius = 25; + config->shadow_config.unfocused.offset = 5; + set_color(config->shadow_config.unfocused.color, 0x000000); + + config->shadow_config.urgent.radius = 25; + config->shadow_config.urgent.offset = 5; + set_color(config->shadow_config.urgent.color, 0x402020); + // Security if (!(config->command_policies = create_list())) goto cleanup; if (!(config->feature_policies = create_list())) goto cleanup; diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 6bea56569..595cc1e5d 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -27,6 +27,10 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" +#if HAVE_SHADOWS +#include +#endif + struct render_data { pixman_region32_t *damage; float alpha; @@ -269,12 +273,238 @@ static void render_saved_view(struct sway_view *view, &box, matrix, alpha); } +#if HAVE_SHADOWS + +static bool check_shader_compilation(unsigned shader, const char* type) { + int success; + char infoLog[1024]; + if (strcmp(type,"PROGRAM") != 0) { + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(shader, 1024, NULL, infoLog); + sway_log(SWAY_ERROR, "ERROR::SHADER_COMPILATION_ERROR of type: %s ", type); + sway_log(SWAY_ERROR, "%s", infoLog); + sway_log(SWAY_ERROR, " -- --------------------------------------------------- -- "); + } + } else { + glGetProgramiv(shader, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shader, 1024, NULL, infoLog); + sway_log(SWAY_ERROR, "ERROR::SHADER_LINKING_ERROR of type: %s ", type); + sway_log(SWAY_ERROR, "%s", infoLog); + sway_log(SWAY_ERROR, " -- --------------------------------------------------- -- "); + } + } + return !!success; +} + +static unsigned shadow_shader = 0; + +void output_init_shadow_shader() { + if (shadow_shader != 0) return; + sway_log(SWAY_INFO, "Initializing shadow shader"); + static const char* vcode = + "uniform mat3 proj;\n" + "uniform vec4 color;\n" + "attribute vec2 pos;\n" + "attribute vec2 texcoord;\n" + "varying vec4 v_color;\n" + "varying vec2 v_texcoord;\n" + "\n" + "void main() {\n" + " gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" + " v_color = color;\n" + " v_texcoord = texcoord;\n" + "}\n"; + + static const char* fcode = + "precision mediump float; \n" + "varying vec4 v_color; \n" + "varying vec2 v_texcoord; \n" + "uniform float aspect; \n" + "uniform float radius; \n" + " \n" + "void main() \n" + "{ \n" + " vec2 pos = v_texcoord; \n" + " \n" + " //pos.x /= aspect; \n" + " \n" + " float dx = smoothstep(0.0, radius * aspect, min(pos.x, 1.0 - pos.x)); \n" + " float dy = smoothstep(0.0, radius, min(pos.y, 1.0 - pos.y)); \n" + " \n" + " float alpha = dx * dy; \n" + " gl_FragColor = vec4(v_color.rgb, v_color.a * alpha); \n" + "} \n"; + + unsigned int vertex, fragment; + + unsigned int shader; + vertex = glCreateShader(GL_VERTEX_SHADER); + sway_log(SWAY_INFO, "vertex shader: %d", vertex); + glShaderSource(vertex, 1, &vcode, NULL); + glCompileShader(vertex); + bool failed = !check_shader_compilation(vertex, "VERTEX"); + + fragment = glCreateShader(GL_FRAGMENT_SHADER); + sway_log(SWAY_INFO, "fragment shader: %d", fragment); + glShaderSource(fragment, 1, &fcode, NULL); + glCompileShader(fragment); + failed |= !check_shader_compilation(fragment, "FRAGMENT"); + + shader = glCreateProgram(); + glAttachShader(shader, vertex); + glAttachShader(shader, fragment); + glLinkProgram(shader); + failed |= !check_shader_compilation(shader, "PROGRAM"); + + glDeleteShader(vertex); + glDeleteShader(fragment); + if (!failed) { + shadow_shader = shader; + } else { + sway_log(SWAY_ERROR, "Failure initializing shadow shader"); + } +} + +static void draw_quad() +{ + GLfloat verts[] = { + 1, 0, // top right + 0, 0, // top left + 1, 1, // bottom right + 0, 1, // bottom left + }; + GLfloat texcoord[] = { + 1, 0, // top right + 0, 0, // top left + 1, 1, // bottom right + 0, 1, // bottom left + }; + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); +} + +static void render_shadow(struct sway_output *output, pixman_region32_t *output_damage, struct wlr_box box, + float rotation, float alpha, struct shadow_config* shadow) { + + if (shadow_shader == 0) return; + + float offset = shadow->offset, radius = shadow->radius; + + box.x += offset - radius / 2.f; + box.y += offset - radius / 2.f; + box.height += radius; + box.width += radius; + + struct wlr_output *wlr_output = output->wlr_output; + // struct wlr_renderer *renderer = + // wlr_backend_get_renderer(wlr_output->backend); + + box.x -= output->lx * wlr_output->scale; + box.y -= output->ly * wlr_output->scale; + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_union_rect( + &damage, &damage, box.x, box.y, box.width, box.height); + pixman_region32_intersect(&damage, &damage, output_damage); + bool damaged = pixman_region32_not_empty(&damage); + if (!damaged) { + goto damage_finish; + } + + float matrix[9]; + wlr_matrix_project_box(matrix, + &box, + WL_OUTPUT_TRANSFORM_NORMAL, + rotation, + wlr_output->transform_matrix); + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(output->wlr_output, &rects[i]); + + float transposition[9]; + wlr_matrix_transpose(transposition, matrix); + + // save current shader and blend settings + GLint prevShader; + glGetIntegerv(GL_CURRENT_PROGRAM, &prevShader); + GLboolean blendEnabled; + glGetBooleanv(GL_BLEND, &blendEnabled); + GLint blendSrc; + GLint blendDst; + glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrc); + glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDst); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glUseProgram(shadow_shader); + + // update the uniform color + glUniformMatrix3fv(glGetUniformLocation(shadow_shader, "proj"), + 1, + false, + transposition); + glUniform4f(glGetUniformLocation(shadow_shader, "color"), + shadow->color[0], + shadow->color[1], + shadow->color[2], + alpha); + glUniform1f(glGetUniformLocation(shadow_shader, "aspect"), + box.height / (float)box.width); + glUniform1f(glGetUniformLocation(shadow_shader, "radius"), + radius / (float)box.height); + draw_quad(); + + // restore state + glUseProgram(prevShader); + if (blendEnabled) glEnable(GL_BLEND); + else glDisable(GL_BLEND); + glBlendFunc(blendSrc, blendDst); + } + +damage_finish: + pixman_region32_fini(&damage); +} + +static void render_shadow_for_view(struct sway_output *output, pixman_region32_t *damage, + struct sway_container *con, struct shadow_config *shadow) { + + float output_scale = output->wlr_output->scale; + struct sway_container_state *state = &con->current; + + struct wlr_box shadow_box = {state->x, state->content_y, state->width, state->height}; + scale_box(&shadow_box, output_scale); + render_shadow(output, damage, shadow_box, 0, con->alpha, shadow); +} +#else +void output_init_shadow_shader() {} + +static void render_shadow_for_view(struct sway_output *output, pixman_region32_t *damage, + struct sway_container *con, struct shadow_config *shadow) { + +#endif +// SHADOWS END + /** * Render a view's surface and left/bottom/right borders. */ static void render_view(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, struct border_colors *colors) { struct sway_view *view = con->view; + if (view->saved_buffer) { render_saved_view(view, output, damage, view->container->alpha); } else if (view->surface) { @@ -285,11 +515,12 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, return; } - struct wlr_box box; float output_scale = output->wlr_output->scale; - float color[4]; struct sway_container_state *state = &con->current; + struct wlr_box box; + float color[4]; + if (state->border_left) { memcpy(&color, colors->child_border, sizeof(float) * 4); premultiply_alpha(color, con->alpha); @@ -678,28 +909,35 @@ static void render_containers_linear(struct sway_output *output, if (child->view) { struct sway_view *view = child->view; struct border_colors *colors; + struct shadow_config *shadow; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; struct sway_container_state *state = &child->current; if (view_is_urgent(view)) { colors = &config->border_colors.urgent; + shadow = &config->shadow_config.urgent; title_texture = child->title_urgent; marks_texture = child->marks_urgent; } else if (state->focused || parent->focused) { colors = &config->border_colors.focused; + shadow = &config->shadow_config.focused; title_texture = child->title_focused; marks_texture = child->marks_focused; } else if (child == parent->active_child) { colors = &config->border_colors.focused_inactive; + shadow = &config->shadow_config.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = child->marks_focused_inactive; } else { colors = &config->border_colors.unfocused; + shadow = &config->shadow_config.unfocused; title_texture = child->title_unfocused; marks_texture = child->marks_unfocused; } + render_shadow_for_view(output, damage, child, shadow); + if (state->border == B_NORMAL) { render_titlebar(output, damage, child, state->x, state->y, state->width, colors, @@ -727,6 +965,32 @@ static void render_containers_tabbed(struct sway_output *output, struct border_colors *current_colors = &config->border_colors.unfocused; int tab_width = parent->box.width / parent->children->length; +#if HAVE_SHADOWS + struct shadow_config *current_shadow = &config->shadow_config.unfocused; + + // Render shadow + for (int i = 0; i < parent->children->length; ++i) { + struct sway_container *child = parent->children->items[i]; + struct sway_view *view = child->view; + struct sway_container_state *cstate = &child->current; + bool urgent = view ? + view_is_urgent(view) : container_has_urgent_child(child); + + if (child == current) { + if (urgent) { + current_shadow = &config->shadow_config.urgent; + } else if (cstate->focused || parent->focused) { + current_shadow = &config->shadow_config.focused; + } else if (child == parent->active_child) { + current_shadow = &config->shadow_config.focused_inactive; + } else { + current_shadow = &config->shadow_config.unfocused; + } + } + } + render_shadow_for_view(output, damage, current, current_shadow); +#endif + // Render tabs for (int i = 0; i < parent->children->length; ++i) { struct sway_container *child = parent->children->items[i]; @@ -790,14 +1054,42 @@ static void render_containers_stacked(struct sway_output *output, } struct sway_container *current = parent->active_child; struct border_colors *current_colors = &config->border_colors.unfocused; + struct shadow_config *current_shadows = &config->shadow_config.unfocused; size_t titlebar_height = container_titlebar_height(); +#if HAVE_SHADOWS + struct shadow_config *current_shadow = &config->shadow_config.unfocused; + + // Render shadow + for (int i = 0; i < parent->children->length; ++i) { + struct sway_container *child = parent->children->items[i]; + struct sway_view *view = child->view; + struct sway_container_state *cstate = &child->current; + bool urgent = view ? + view_is_urgent(view) : container_has_urgent_child(child); + + if (child == current) { + if (urgent) { + current_shadow = &config->shadow_config.urgent; + } else if (cstate->focused || parent->focused) { + current_shadow = &config->shadow_config.focused; + } else if (child == parent->active_child) { + current_shadow = &config->shadow_config.focused_inactive; + } else { + current_shadow = &config->shadow_config.unfocused; + } + } + } + render_shadow_for_view(output, damage, current, current_shadow); +#endif + // Render titles for (int i = 0; i < parent->children->length; ++i) { struct sway_container *child = parent->children->items[i]; struct sway_view *view = child->view; struct sway_container_state *cstate = &child->current; struct border_colors *colors; + struct shadow_config *shadows; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; bool urgent = view ? @@ -805,18 +1097,22 @@ static void render_containers_stacked(struct sway_output *output, if (urgent) { colors = &config->border_colors.urgent; + shadows = &config->shadow_config.urgent; title_texture = child->title_urgent; marks_texture = child->marks_urgent; } else if (cstate->focused || parent->focused) { colors = &config->border_colors.focused; + shadows = &config->shadow_config.focused; title_texture = child->title_focused; marks_texture = child->marks_focused; } else if (child == parent->active_child) { colors = &config->border_colors.focused_inactive; + shadows = &config->shadow_config.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = child->marks_focused_inactive; } else { colors = &config->border_colors.unfocused; + shadows = &config->shadow_config.unfocused; title_texture = child->title_unfocused; marks_texture = child->marks_unfocused; } @@ -827,6 +1123,7 @@ static void render_containers_stacked(struct sway_output *output, if (child == current) { current_colors = colors; + current_shadows = shadows; } } @@ -903,23 +1200,29 @@ static void render_floating_container(struct sway_output *soutput, if (con->view) { struct sway_view *view = con->view; struct border_colors *colors; + struct shadow_config *shadows; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; if (view_is_urgent(view)) { colors = &config->border_colors.urgent; + shadows = &config->shadow_config.urgent; title_texture = con->title_urgent; marks_texture = con->marks_urgent; } else if (con->current.focused) { colors = &config->border_colors.focused; + shadows = &config->shadow_config.focused; title_texture = con->title_focused; marks_texture = con->marks_focused; } else { colors = &config->border_colors.unfocused; + shadows = &config->shadow_config.unfocused; title_texture = con->title_unfocused; marks_texture = con->marks_unfocused; } + render_shadow_for_view(soutput, damage, con, shadows); + if (con->current.border == B_NORMAL) { render_titlebar(soutput, damage, con, con->current.x, con->current.y, con->current.width, colors, diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 7a65be075..bef7cc6e2 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -339,6 +339,11 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace, json_object_new_string( ipc_json_orientation_description(workspace->layout))); + json_object *gaps = json_object_new_object(); + json_object_object_add(gaps, "inner", json_object_new_int(workspace->gaps_inner)); + // Add outer + json_object_object_add(object, "gaps", gaps); + // Floating json_object *floating_array = json_object_new_array(); for (int i = 0; i < workspace->floating->length; ++i) { diff --git a/sway/meson.build b/sway/meson.build index 99dab7e78..8d7006309 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -111,6 +111,7 @@ sway_sources = files( 'commands/workspace_layout.c', 'commands/ws_auto_back_and_forth.c', 'commands/xwayland.c', + 'commands/shadows.c', 'commands/bar/bind.c', 'commands/bar/binding_mode_indicator.c', diff --git a/sway/tree/output.c b/sway/tree/output.c index 24adc08d6..87c548c82 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -101,6 +101,8 @@ struct sway_output *output_create(struct wlr_output *wlr_output) { output->workspaces = create_list(); output->current.workspaces = create_list(); + output_init_shadow_shader(); + return output; }