summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/meson.build2
-rw-r--r--examples/scene-graph.c15
-rw-r--r--include/render/fx_renderer/shaders.h4
-rw-r--r--include/scenefx/render/pass.h9
-rw-r--r--include/scenefx/types/fx/shadow_data.h20
-rw-r--r--include/scenefx/types/wlr_scene.h51
-rw-r--r--render/fx_renderer/fx_pass.c50
-rw-r--r--render/fx_renderer/gles2/shaders/box_shadow.frag10
-rw-r--r--render/fx_renderer/shaders.c4
-rw-r--r--tinywl/tinywl.c56
-rw-r--r--types/fx/meson.build1
-rw-r--r--types/fx/shadow_data.c15
-rw-r--r--types/scene/wlr_scene.c260
13 files changed, 336 insertions, 161 deletions
diff --git a/examples/meson.build b/examples/meson.build
index da32934..dc6f171 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -17,7 +17,7 @@ foreach name, info : compositors
executable(
name,
[info.get('src'), extra_src],
- dependencies: [wlroots, scenefx, libdrm_header, info.get('dep', [])],
+ dependencies: [scenefx, libdrm_header, info.get('dep', [])],
build_by_default: get_option('examples'),
)
endforeach
diff --git a/examples/scene-graph.c b/examples/scene-graph.c
index 562f72e..e2e7d19 100644
--- a/examples/scene-graph.c
+++ b/examples/scene-graph.c
@@ -2,6 +2,7 @@
#include <assert.h>
#include <getopt.h>
#include <scenefx/render/fx_renderer/fx_renderer.h>
+#include <scenefx/types/wlr_scene.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -13,7 +14,6 @@
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_output.h>
-#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
@@ -22,6 +22,7 @@
* New surfaces are stacked on top of the existing ones as they appear. */
static const int border_width = 3;
+static const int corner_radius = 0; // TODO
struct server {
struct wl_display *display;
@@ -40,6 +41,7 @@ struct surface {
struct wlr_surface *wlr;
struct wlr_scene_surface *scene_surface;
struct wlr_scene_rect *border;
+ struct wlr_scene_shadow *shadow;
struct wl_list link;
struct wl_listener commit;
@@ -99,12 +101,16 @@ static void surface_handle_commit(struct wl_listener *listener, void *data) {
wlr_scene_rect_set_size(surface->border,
surface->wlr->current.width + 2 * border_width,
surface->wlr->current.height + 2 * border_width);
+ wlr_scene_shadow_set_size(surface->shadow,
+ surface->wlr->current.width + 2 * (surface->shadow->blur_sigma + border_width),
+ surface->wlr->current.height + 2 * (surface->shadow->blur_sigma + border_width));
}
static void surface_handle_destroy(struct wl_listener *listener, void *data) {
struct surface *surface = wl_container_of(listener, surface, destroy);
wlr_scene_node_destroy(&surface->scene_surface->buffer->node);
wlr_scene_node_destroy(&surface->border->node);
+ wlr_scene_node_destroy(&surface->shadow->node);
wl_list_remove(&surface->destroy.link);
wl_list_remove(&surface->link);
free(surface);
@@ -130,8 +136,15 @@ static void server_handle_new_surface(struct wl_listener *listener,
0, 0, (float[4]){ 0.5f, 0.5f, 0.5f, 1 });
wlr_scene_node_set_position(&surface->border->node, pos, pos);
+ /* Shadow dimensions will be set in surface.commit handler */
+ float blur_sigma = 20.0f;
+ surface->shadow = wlr_scene_shadow_create(&server->scene->tree,
+ 0, 0, corner_radius, blur_sigma, (float[4]){ 1.0f, 0.f, 0.f, 1.0f });
+ wlr_scene_node_set_position(&surface->shadow->node,
+ pos - blur_sigma, pos - blur_sigma);
surface->scene_surface =
wlr_scene_surface_create(&server->scene->tree, wlr_surface);
+ wlr_scene_buffer_set_corner_radius(surface->scene_surface->buffer, corner_radius);
wlr_scene_node_set_position(&surface->scene_surface->buffer->node,
pos + border_width, pos + border_width);
diff --git a/include/render/fx_renderer/shaders.h b/include/render/fx_renderer/shaders.h
index 6c19744..df91762 100644
--- a/include/render/fx_renderer/shaders.h
+++ b/include/render/fx_renderer/shaders.h
@@ -91,9 +91,11 @@ struct box_shadow_shader {
GLint pos_attrib;
GLint position;
GLint size;
- GLint offset;
GLint blur_sigma;
GLint corner_radius;
+ GLint window_position;
+ GLint window_half_size;
+ GLint window_corner_radius;
};
bool link_box_shadow_program(struct box_shadow_shader *shader);
diff --git a/include/scenefx/render/pass.h b/include/scenefx/render/pass.h
index d005c37..9e92f90 100644
--- a/include/scenefx/render/pass.h
+++ b/include/scenefx/render/pass.h
@@ -4,7 +4,6 @@
#include <stdbool.h>
#include <wlr/render/pass.h>
#include <wlr/render/interface.h>
-#include "scenefx/types/fx/shadow_data.h"
struct fx_gles_render_pass {
struct wlr_render_pass base;
@@ -43,13 +42,15 @@ struct fx_render_rect_options {
};
struct fx_render_box_shadow_options {
- struct wlr_box shadow_box;
- struct wlr_box clip_box;
+ struct wlr_box box;
+ struct wlr_box window_box;
+ int window_corner_radius;
/* Clip region, leave NULL to disable clipping */
const pixman_region32_t *clip;
- struct shadow_data *shadow_data;
+ float blur_sigma;
int corner_radius;
+ struct wlr_render_color color;
};
struct fx_render_rounded_rect_options {
diff --git a/include/scenefx/types/fx/shadow_data.h b/include/scenefx/types/fx/shadow_data.h
deleted file mode 100644
index c307871..0000000
--- a/include/scenefx/types/fx/shadow_data.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef TYPES_DECORATION_DATA
-#define TYPES_DECORATION_DATA
-
-#include <stdbool.h>
-#include <wlr/util/addon.h>
-#include <wlr/render/pass.h>
-
-struct shadow_data {
- bool enabled;
- struct wlr_render_color color;
- float blur_sigma;
- float offset_x;
- float offset_y;
-};
-
-struct shadow_data shadow_data_get_default(void);
-
-bool scene_buffer_has_shadow(struct shadow_data *data);
-
-#endif
diff --git a/include/scenefx/types/wlr_scene.h b/include/scenefx/types/wlr_scene.h
index 5925931..9b68c4b 100644
--- a/include/scenefx/types/wlr_scene.h
+++ b/include/scenefx/types/wlr_scene.h
@@ -20,7 +20,6 @@
*/
#include <pixman.h>
-#include "scenefx/types/fx/shadow_data.h"
#include <time.h>
#include <wayland-server-core.h>
#include <wlr/render/wlr_renderer.h>
@@ -54,6 +53,7 @@ typedef void (*wlr_scene_buffer_iterator_func_t)(
enum wlr_scene_node_type {
WLR_SCENE_NODE_TREE,
WLR_SCENE_NODE_RECT,
+ WLR_SCENE_NODE_SHADOW,
WLR_SCENE_NODE_BUFFER,
};
@@ -140,6 +140,15 @@ struct wlr_scene_rect {
float color[4];
};
+/** A scene-graph node displaying a shadow */
+struct wlr_scene_shadow {
+ struct wlr_scene_node node;
+ int width, height;
+ int corner_radius;
+ float color[4];
+ float blur_sigma;
+};
+
struct wlr_scene_outputs_update_event {
struct wlr_scene_output **active;
size_t size;
@@ -178,7 +187,6 @@ struct wlr_scene_buffer {
float opacity;
int corner_radius;
- struct shadow_data shadow_data;
enum wlr_scale_filter_mode filter_mode;
struct wlr_fbox src_box;
@@ -359,6 +367,12 @@ struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node);
struct wlr_scene_rect *wlr_scene_rect_from_node(struct wlr_scene_node *node);
/**
+ * If this node represents a wlr_scene_shadow, that shadow will be returned. It
+ * is not legal to feed a node that does not represent a wlr_scene_shadow.
+ */
+struct wlr_scene_shadow *wlr_scene_shadow_from_node(struct wlr_scene_node *node);
+
+/**
* If this buffer is backed by a surface, then the struct wlr_scene_surface is
* returned. If not, NULL will be returned.
*/
@@ -382,6 +396,33 @@ void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height)
void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]);
/**
+ * Add a node displaying a shadow to the scene-graph.
+ */
+struct wlr_scene_shadow *wlr_scene_shadow_create(struct wlr_scene_tree *parent,
+ int width, int height, int corner_radius, float blur_sigma,
+ const float color[static 4]);
+
+/**
+ * Change the width and height of an existing shadow node.
+ */
+void wlr_scene_shadow_set_size(struct wlr_scene_shadow *shadow, int width, int height);
+
+/**
+ * Change the corner radius of an existing shadow node.
+ */
+void wlr_scene_shadow_set_corner_radius(struct wlr_scene_shadow *shadow, int corner_radius);
+
+/**
+ * Change the blur_sigma of an existing shadow node.
+ */
+void wlr_scene_shadow_set_blur_sigma(struct wlr_scene_shadow *shadow, float blur_sigma);
+
+/**
+ * Change the color of an existing shadow node.
+ */
+void wlr_scene_shadow_set_color(struct wlr_scene_shadow *shadow, const float color[static 4]);
+
+/**
* Add a node displaying a buffer to the scene-graph.
*
* If the buffer is NULL, this node will not be displayed.
@@ -457,12 +498,6 @@ void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer,
int radii);
/**
-* Sets the shadow of this buffer
-*/
-void wlr_scene_buffer_set_shadow_data(struct wlr_scene_buffer *scene_buffer,
- struct shadow_data shadow_data);
-
-/**
* Calls the buffer's frame_done signal.
*/
void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer,
diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c
index f0af02b..5d28c27 100644
--- a/render/fx_renderer/fx_pass.c
+++ b/render/fx_renderer/fx_pass.c
@@ -16,7 +16,6 @@
#include "scenefx/render/fx_renderer/fx_renderer.h"
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "scenefx/types/fx/blur_data.h"
-#include "scenefx/types/fx/shadow_data.h"
#define MAX_QUADS 86 // 4kb
@@ -453,28 +452,26 @@ void fx_render_pass_add_rounded_border_corner(struct fx_gles_render_pass *pass,
void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass,
const struct fx_render_box_shadow_options *options) {
struct fx_renderer *renderer = pass->buffer->renderer;
- struct shadow_data *shadow_data = options->shadow_data;
- const struct wlr_render_color *color = &shadow_data->color;
- struct wlr_box shadow_box = options->shadow_box;
- assert(shadow_box.width > 0 && shadow_box.height > 0);
+ struct wlr_box box = options->box;
+ assert(box.width > 0 && box.height > 0);
- struct wlr_box surface_box = options->clip_box;
+ const struct wlr_box window_box = options->window_box;
- pixman_region32_t render_region;
- pixman_region32_init(&render_region);
-
- pixman_region32_t inner_region;
- pixman_region32_init_rect(&inner_region,
- surface_box.x + options->corner_radius * 0.3,
- surface_box.y + options->corner_radius * 0.3,
- fmax(surface_box.width - options->corner_radius * 0.6, 0),
- fmax(surface_box.height - options->corner_radius * 0.6, 0));
- pixman_region32_subtract(&render_region, options->clip, &inner_region);
- pixman_region32_fini(&inner_region);
+ pixman_region32_t clip_region;
+ if (options->clip) {
+ pixman_region32_init(&clip_region);
+ pixman_region32_copy(&clip_region, options->clip);
+ } else {
+ pixman_region32_init_rect(&clip_region, box.x, box.y, box.width, box.height);
+ }
+ pixman_region32_t window_region;
+ pixman_region32_init_rect(&window_region, window_box.x + options->window_corner_radius * 0.3, window_box.y + options->window_corner_radius * 0.3,
+ window_box.width - options->window_corner_radius * 0.6, window_box.height - options->window_corner_radius * 0.6);
+ pixman_region32_subtract(&clip_region, &clip_region, &window_region);
+ pixman_region32_fini(&window_region);
push_fx_debug(renderer);
-
// blending will practically always be needed (unless we have a madman
// who uses opaque shadows with zero sigma), so just enable it
setup_blending(WLR_RENDER_BLEND_MODE_PREMULTIPLIED);
@@ -482,17 +479,18 @@ void fx_render_pass_add_box_shadow(struct fx_gles_render_pass *pass,
glUseProgram(renderer->shaders.box_shadow.program);
- set_proj_matrix(renderer->shaders.box_shadow.proj, pass->projection_matrix, &shadow_box);
+ const struct wlr_render_color *color = &options->color;
+ set_proj_matrix(renderer->shaders.box_shadow.proj, pass->projection_matrix, &box);
glUniform4f(renderer->shaders.box_shadow.color, color->r, color->g, color->b, color->a);
- glUniform1f(renderer->shaders.box_shadow.blur_sigma, shadow_data->blur_sigma);
+ glUniform1f(renderer->shaders.box_shadow.blur_sigma, options->blur_sigma);
glUniform1f(renderer->shaders.box_shadow.corner_radius, options->corner_radius);
- glUniform2f(renderer->shaders.box_shadow.size, shadow_box.width, shadow_box.height);
- glUniform2f(renderer->shaders.box_shadow.offset, options->shadow_data->offset_x, options->shadow_data->offset_y);
- glUniform2f(renderer->shaders.box_shadow.position, shadow_box.x, shadow_box.y);
+ glUniform2f(renderer->shaders.box_shadow.size, box.width, box.height);
+ glUniform2f(renderer->shaders.box_shadow.position, box.x, box.y);
+ glUniform1f(renderer->shaders.box_shadow.window_corner_radius, options->window_corner_radius);
+ glUniform2f(renderer->shaders.box_shadow.window_half_size, window_box.width / 2.0, window_box.height / 2.0);
+ glUniform2f(renderer->shaders.box_shadow.window_position, window_box.x, window_box.y);
- // TODO: also account for options->clip
- render(&shadow_box, &render_region, renderer->shaders.box_shadow.pos_attrib);
- pixman_region32_fini(&render_region);
+ render(&box, &clip_region, renderer->shaders.box_shadow.pos_attrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
diff --git a/render/fx_renderer/gles2/shaders/box_shadow.frag b/render/fx_renderer/gles2/shaders/box_shadow.frag
index 1980434..ff8ac74 100644
--- a/render/fx_renderer/gles2/shaders/box_shadow.frag
+++ b/render/fx_renderer/gles2/shaders/box_shadow.frag
@@ -11,9 +11,11 @@ varying vec2 v_texcoord;
uniform vec2 position;
uniform vec2 size;
-uniform vec2 offset;
uniform float blur_sigma;
uniform float corner_radius;
+uniform vec2 window_position;
+uniform vec2 window_half_size;
+uniform float window_corner_radius;
float gaussian(float x, float sigma) {
const float pi = 3.141592653589793;
@@ -80,8 +82,8 @@ void main() {
// dither the alpha to break up color bands
shadow_alpha += (random() - 0.5) / 128.0;
- // get the window alpha so we can render around the window (fix pixel gap by adding 0.5 to radius)
- float window_alpha = 1.0 - smoothstep(-1.0, 1.0, roundRectSDF((size * 0.5) - blur_sigma, position + blur_sigma, corner_radius + 0.5));
+ // get the window alpha so we can render around the window (fix pixel gap by adding 1.0 to radius)
+ float window_alpha = smoothstep(-1.0, 1.0, roundRectSDF(window_half_size, window_position, window_corner_radius + 1.0));
- gl_FragColor = vec4(v_color.rgb, shadow_alpha) * (1.0 - window_alpha);
+ gl_FragColor = vec4(v_color.rgb, shadow_alpha) * window_alpha;
}
diff --git a/render/fx_renderer/shaders.c b/render/fx_renderer/shaders.c
index 2c2aa7e..3d5d565 100644
--- a/render/fx_renderer/shaders.c
+++ b/render/fx_renderer/shaders.c
@@ -196,9 +196,11 @@ bool link_box_shadow_program(struct box_shadow_shader *shader) {
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->position = glGetUniformLocation(prog, "position");
shader->size = glGetUniformLocation(prog, "size");
- shader->offset = glGetUniformLocation(prog, "offset");
shader->blur_sigma = glGetUniformLocation(prog, "blur_sigma");
shader->corner_radius = glGetUniformLocation(prog, "corner_radius");
+ shader->window_position = glGetUniformLocation(prog, "window_position");
+ shader->window_half_size = glGetUniformLocation(prog, "window_half_size");
+ shader->window_corner_radius = glGetUniformLocation(prog, "window_corner_radius");
return true;
}
diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c
index c7dfa3a..973780a 100644
--- a/tinywl/tinywl.c
+++ b/tinywl/tinywl.c
@@ -6,7 +6,6 @@
#include <stdio.h>
#include <time.h>
#include <scenefx/render/fx_renderer/fx_renderer.h>
-#include <scenefx/types/fx/shadow_data.h>
#include <scenefx/types/wlr_scene.h>
#include <unistd.h>
#include <wayland-server-core.h>
@@ -85,9 +84,11 @@ struct tinywl_toplevel {
struct wl_list link;
struct tinywl_server *server;
struct wlr_xdg_toplevel *xdg_toplevel;
+ struct wlr_scene_tree *xdg_scene_tree;
struct wlr_scene_tree *scene_tree;
struct wl_listener map;
struct wl_listener unmap;
+ struct wl_listener commit;
struct wl_listener destroy;
struct wl_listener request_move;
struct wl_listener request_resize;
@@ -96,7 +97,7 @@ struct tinywl_toplevel {
float opacity;
int corner_radius;
- struct shadow_data shadow_data;
+ struct wlr_scene_shadow *shadow;
};
struct tinywl_keyboard {
@@ -583,13 +584,10 @@ static void output_configure_scene(struct wlr_scene_node *node,
if (toplevel &&
xdg_surface &&
xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
- // TODO: Be able to set whole decoration_data instead of calling
- // each individually?
wlr_scene_buffer_set_opacity(buffer, toplevel->opacity);
if (!wlr_subsurface_try_from_wlr_surface(xdg_surface->surface)) {
wlr_scene_buffer_set_corner_radius(buffer, toplevel->corner_radius);
- wlr_scene_buffer_set_shadow_data(buffer, toplevel->shadow_data);
}
}
} else if (node->type == WLR_SCENE_NODE_TREE) {
@@ -707,15 +705,30 @@ static void xdg_toplevel_map(struct wl_listener *listener, void *data) {
/* Called when the surface is mapped, or ready to display on-screen. */
struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, map);
+ wlr_scene_node_set_enabled(&toplevel->scene_tree->node, true);
+
wl_list_insert(&toplevel->server->toplevels, &toplevel->link);
- focus_toplevel(toplevel, toplevel->xdg_toplevel->base->surface);
+ struct wlr_surface *surface = toplevel->xdg_toplevel->base->surface;
+
+ int blur_sigma = toplevel->shadow->blur_sigma;
+ struct wlr_box geometry;
+ wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geometry);
+ wlr_scene_shadow_set_size(toplevel->shadow,
+ geometry.width + blur_sigma * 2,
+ geometry.height + blur_sigma * 2);
+
+ wlr_scene_node_set_position(&toplevel->shadow->node, -blur_sigma, -blur_sigma);
+
+ focus_toplevel(toplevel, surface);
}
static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) {
/* Called when the surface is unmapped, and should no longer be shown. */
struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, unmap);
+ wlr_scene_node_set_enabled(&toplevel->scene_tree->node, false);
+
/* Reset the cursor mode if the grabbed toplevel was unmapped. */
if (toplevel == toplevel->server->grabbed_toplevel) {
reset_cursor_mode(toplevel->server);
@@ -724,18 +737,33 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) {
wl_list_remove(&toplevel->link);
}
+static void xdg_toplevel_commit(struct wl_listener *listener, void *data) {
+ struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, commit);
+
+ struct wlr_box geometry;
+ wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geometry);
+ wlr_scene_subsurface_tree_set_clip(&toplevel->xdg_scene_tree->node, &geometry);
+
+ int blur_sigma = toplevel->shadow->blur_sigma;
+ wlr_scene_shadow_set_size(toplevel->shadow,
+ geometry.width + blur_sigma * 2, geometry.height + blur_sigma * 2);
+}
+
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) {
/* Called when the xdg_toplevel is destroyed. */
struct tinywl_toplevel *toplevel = wl_container_of(listener, toplevel, destroy);
wl_list_remove(&toplevel->map.link);
wl_list_remove(&toplevel->unmap.link);
+ wl_list_remove(&toplevel->commit.link);
wl_list_remove(&toplevel->destroy.link);
wl_list_remove(&toplevel->request_move.link);
wl_list_remove(&toplevel->request_resize.link);
wl_list_remove(&toplevel->request_maximize.link);
wl_list_remove(&toplevel->request_fullscreen.link);
+ wlr_scene_node_destroy(&toplevel->scene_tree->node);
+
free(toplevel);
}
@@ -847,23 +875,29 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) {
struct tinywl_toplevel *toplevel = calloc(1, sizeof(*toplevel));
toplevel->server = server;
toplevel->xdg_toplevel = xdg_surface->toplevel;
- toplevel->scene_tree = wlr_scene_xdg_surface_create(
- &toplevel->server->scene->tree, toplevel->xdg_toplevel->base);
+ toplevel->scene_tree = wlr_scene_tree_create(&toplevel->server->scene->tree);
+ toplevel->xdg_scene_tree = wlr_scene_xdg_surface_create(
+ toplevel->scene_tree, toplevel->xdg_toplevel->base);
toplevel->scene_tree->node.data = toplevel;
xdg_surface->data = toplevel->scene_tree;
/* Set the scene_nodes decoration data */
toplevel->opacity = 1;
toplevel->corner_radius = 20;
- toplevel->shadow_data = shadow_data_get_default();
- toplevel->shadow_data.enabled = true;
- toplevel->shadow_data.color = (struct wlr_render_color) {1.0f, 0.0f, 0.0f, 1.0f};
+
+ float blur_sigma = 20.0f;
+ toplevel->shadow = wlr_scene_shadow_create(toplevel->scene_tree,
+ 0, 0, toplevel->corner_radius, blur_sigma, (float[4]){ 1.0f, 0.f, 0.f, 1.0f });
+ // Lower the shadow below the XDG scene tree
+ wlr_scene_node_lower_to_bottom(&toplevel->shadow->node);
/* Listen to the various events it can emit */
toplevel->map.notify = xdg_toplevel_map;
wl_signal_add(&xdg_surface->surface->events.map, &toplevel->map);
toplevel->unmap.notify = xdg_toplevel_unmap;
wl_signal_add(&xdg_surface->surface->events.unmap, &toplevel->unmap);
+ toplevel->commit.notify = xdg_toplevel_commit;
+ wl_signal_add(&xdg_surface->surface->events.commit, &toplevel->commit);
toplevel->destroy.notify = xdg_toplevel_destroy;
wl_signal_add(&xdg_surface->events.destroy, &toplevel->destroy);
diff --git a/types/fx/meson.build b/types/fx/meson.build
index 3932965..d8bef8c 100644
--- a/types/fx/meson.build
+++ b/types/fx/meson.build
@@ -1,4 +1,3 @@
scenefx_files += files(
- 'shadow_data.c',
'blur_data.c',
)
diff --git a/types/fx/shadow_data.c b/types/fx/shadow_data.c
deleted file mode 100644
index d74cadc..0000000
--- a/types/fx/shadow_data.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "scenefx/types/fx/shadow_data.h"
-
-struct shadow_data shadow_data_get_default(void) {
- return (struct shadow_data) {
- .blur_sigma = 20,
- .color = {0.0f, 0.0f, 0.0f, 0.5f},
- .enabled = false,
- .offset_x = 0.0f,
- .offset_y = 0.0f,
- };
-}
-
-bool scene_buffer_has_shadow(struct shadow_data *data) {
- return data->enabled && data->blur_sigma > 0 && data->color.a > 0.0;
-}
diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
index 2f4dd45..e5d4f39 100644
--- a/types/scene/wlr_scene.c
+++ b/types/scene/wlr_scene.c
@@ -2,7 +2,6 @@
#include <assert.h>
#include <pixman.h>
#include <stdlib.h>
-#include <scenefx/types/fx/shadow_data.h>
#include <scenefx/types/wlr_scene.h>
#include <string.h>
#include <wlr/backend.h>
@@ -18,7 +17,6 @@
#include <wlr/render/swapchain.h>
#include "scenefx/render/pass.h"
-#include "scenefx/types/fx/shadow_data.h"
#include "types/wlr_buffer.h"
#include "types/wlr_output.h"
#include "types/wlr_scene.h"
@@ -47,6 +45,12 @@ struct wlr_scene_buffer *wlr_scene_buffer_from_node(
return buffer;
}
+struct wlr_scene_shadow *wlr_scene_shadow_from_node(struct wlr_scene_node *node) {
+ assert(node->type == WLR_SCENE_NODE_SHADOW);
+ struct wlr_scene_shadow *shadow = wl_container_of(node, shadow, node);
+ return shadow;
+}
+
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) {
struct wlr_scene_tree *tree;
if (node->type == WLR_SCENE_NODE_TREE) {
@@ -214,6 +218,7 @@ static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box
}
break;
case WLR_SCENE_NODE_RECT:
+ case WLR_SCENE_NODE_SHADOW:
case WLR_SCENE_NODE_BUFFER:;
struct wlr_box node_box = { .x = lx, .y = ly };
scene_node_get_size(node, &node_box.width, &node_box.height);
@@ -246,6 +251,9 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
if (scene_rect->color[3] != 1) {
return;
}
+ } else if (node->type == WLR_SCENE_NODE_SHADOW) {
+ // TODO: test & handle case of blur sigma = 0 and color[3] = 1?
+ return;
} else if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
@@ -258,10 +266,7 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
}
if (scene_buffer->corner_radius > 0) {
- return;
- }
-
- if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) {
+ // TODO: this is incorrect
return;
}
@@ -474,24 +479,6 @@ static bool scene_node_update_iterator(struct wlr_scene_node *node,
pixman_region32_fini(&opaque);
}
- // Expand the nodes visible region by the shadow size
- if (node->type == WLR_SCENE_NODE_BUFFER) {
- struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
- struct shadow_data *shadow_data = &buffer->shadow_data;
- if (scene_buffer_has_shadow(shadow_data)) {
- // Expand towards the damage while also compensating for the x and y
- // offsets
- pixman_region32_t shadow;
- pixman_region32_init(&shadow);
- pixman_region32_copy(&shadow, &node->visible);
- wlr_region_expand(&shadow, &shadow, shadow_data->blur_sigma);
- pixman_region32_translate(&shadow, shadow_data->offset_x, shadow_data->offset_y);
- pixman_region32_subtract(&shadow, &shadow, &node->visible);
- pixman_region32_union(&node->visible, &node->visible, &shadow);
- pixman_region32_fini(&shadow);
- }
- }
-
update_node_update_outputs(node, data->outputs, NULL, NULL);
return false;
@@ -634,6 +621,64 @@ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[sta
scene_node_update(&rect->node, NULL);
}
+struct wlr_scene_shadow *wlr_scene_shadow_create(struct wlr_scene_tree *parent,
+ int width, int height, int corner_radius, float blur_sigma,
+ const float color [static 4]) {
+ struct wlr_scene_shadow *scene_shadow = calloc(1, sizeof(*scene_shadow));
+ if (scene_shadow == NULL) {
+ return NULL;
+ }
+ assert(parent);
+ scene_node_init(&scene_shadow->node, WLR_SCENE_NODE_SHADOW, parent);
+
+ scene_shadow->width = width;
+ scene_shadow->height = height;
+ scene_shadow->corner_radius = corner_radius;
+ scene_shadow->blur_sigma = blur_sigma;
+ memcpy(scene_shadow->color, color, sizeof(scene_shadow->color));
+
+ scene_node_update(&scene_shadow->node, NULL);
+
+ return scene_shadow;
+}
+
+void wlr_scene_shadow_set_size(struct wlr_scene_shadow *shadow, int width, int height) {
+ if (shadow->width == width && shadow->height == height) {
+ return;
+ }
+
+ shadow->width = width;
+ shadow->height = height;
+ scene_node_update(&shadow->node, NULL);
+}
+
+void wlr_scene_shadow_set_corner_radius(struct wlr_scene_shadow *shadow, int corner_radius) {
+ if (shadow->corner_radius == corner_radius) {
+ return;
+ }
+
+ shadow->corner_radius = corner_radius;
+ scene_node_update(&shadow->node, NULL);
+}
+
+void wlr_scene_shadow_set_blur_sigma(struct wlr_scene_shadow *shadow, float blur_sigma) {
+ if (shadow->blur_sigma == blur_sigma) {
+ return;
+ }
+
+ shadow->blur_sigma = blur_sigma;
+ scene_node_update(&shadow->node, NULL);
+}
+
+void wlr_scene_shadow_set_color(struct wlr_scene_shadow *shadow, const float color[static 4]) {
+ if (memcmp(shadow->color, color, sizeof(shadow->color)) == 0) {
+ return;
+ }
+
+ memcpy(shadow->color, color, sizeof(shadow->color));
+ scene_node_update(&shadow->node, NULL);
+}
+
struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
struct wlr_buffer *buffer) {
struct wlr_scene_buffer *scene_buffer = calloc(1, sizeof(*scene_buffer));
@@ -655,7 +700,6 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
pixman_region32_init(&scene_buffer->opaque_region);
scene_buffer->opacity = 1;
scene_buffer->corner_radius = 0;
- scene_buffer->shadow_data = shadow_data_get_default();
scene_node_update(&scene_buffer->node, NULL);
@@ -886,25 +930,6 @@ void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer,
scene_node_update(&scene_buffer->node, NULL);
}
-void wlr_scene_buffer_set_shadow_data(struct wlr_scene_buffer *scene_buffer,
- struct shadow_data shadow_data) {
- struct shadow_data *buff_data = &scene_buffer->shadow_data;
- if (buff_data->enabled == shadow_data.enabled &&
- buff_data->blur_sigma == shadow_data.blur_sigma &&
- buff_data->offset_x == shadow_data.offset_x &&
- buff_data->offset_y == shadow_data.offset_y &&
- buff_data->color.r && shadow_data.color.r &&
- buff_data->color.g && shadow_data.color.g &&
- buff_data->color.b && shadow_data.color.b &&
- buff_data->color.a && shadow_data.color.a) {
- return;
- }
-
- memcpy(&scene_buffer->shadow_data, &shadow_data,
- sizeof(struct shadow_data));
- scene_node_update(&scene_buffer->node, NULL);
-}
-
static struct wlr_texture *scene_buffer_get_texture(
struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) {
struct wlr_client_buffer *client_buffer =
@@ -935,6 +960,12 @@ static void scene_node_get_size(struct wlr_scene_node *node,
*width = scene_rect->width;
*height = scene_rect->height;
break;
+ case WLR_SCENE_NODE_SHADOW:;
+ // TODO: compensate for blur_sigma? may not be needed
+ struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node);
+ *width = scene_shadow->width;
+ *height = scene_shadow->height;
+ break;
case WLR_SCENE_NODE_BUFFER:;
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) {
@@ -953,6 +984,25 @@ static void scene_node_get_size(struct wlr_scene_node *node,
}
}
+static void scene_node_get_corner_radius(struct wlr_scene_node *node, int *corner_radius) {
+ *corner_radius = 0;
+
+ switch (node->type) {
+ case WLR_SCENE_NODE_TREE:
+ return;
+ case WLR_SCENE_NODE_RECT:;
+ return;
+ case WLR_SCENE_NODE_SHADOW:;
+ struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node);
+ *corner_radius = scene_shadow->corner_radius;
+ break;
+ case WLR_SCENE_NODE_BUFFER:;
+ struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
+ *corner_radius = scene_buffer->corner_radius;
+ break;
+ }
+}
+
static int scale_length(int length, int offset, float scale) {
return round((offset + length) * scale) - round(offset * scale);
}
@@ -1133,6 +1183,9 @@ static bool scene_node_at_iterator(struct wlr_scene_node *node,
!scene_buffer->point_accepts_input(scene_buffer, &rx, &ry)) {
return false;
}
+ } else if (node->type == WLR_SCENE_NODE_SHADOW) {
+ // Disable interaction
+ return false;
}
at_data->rx = rx;
@@ -1168,6 +1221,67 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
return NULL;
}
+static void get_tree_geometry(struct wlr_scene_node *node,
+ pixman_region32_t *region, int *max_corner_radius) {
+ if (!node->enabled) {
+ return;
+ }
+
+ if (node->type == WLR_SCENE_NODE_BUFFER || node->type == WLR_SCENE_NODE_RECT) {
+ struct wlr_box child_box = {0};
+ int radius = 0;
+ wlr_scene_node_coords(node, &child_box.x, &child_box.y);
+ scene_node_get_size(node, &child_box.width, &child_box.height);
+ scene_node_get_corner_radius(node, &radius);
+
+ pixman_region32_union_rect(region, region,
+ child_box.x, child_box.y, child_box.width, child_box.height);
+ if (radius > *max_corner_radius) {
+ *max_corner_radius = radius;
+ }
+ } else if (node->type == WLR_SCENE_NODE_TREE) {
+ struct wlr_scene_tree *tree = wlr_scene_tree_from_node(node);
+ struct wlr_scene_node *node;
+ wl_list_for_each(node, &tree->children, link) {
+ // Could possibly be a tree, so look through it as well
+ get_tree_geometry(node, region, max_corner_radius);
+ }
+ }
+}
+
+static void scene_get_next_sibling_geometry(struct wlr_scene_node *node,
+ struct wlr_box *box, int *corner_radius) {
+ assert(box && corner_radius);
+
+ *box = (struct wlr_box) {0};
+ *corner_radius = 0;
+
+ // Don't check if it's the only child in the tree
+ if (node->link.next == node->link.prev) {
+ return;
+ }
+
+ struct wlr_scene_node *sibling_node =
+ wl_container_of(node->link.next, sibling_node, link);
+
+ pixman_region32_t region;
+ pixman_region32_init(&region);
+
+ get_tree_geometry(sibling_node, &region, corner_radius);
+
+ if (pixman_region32_not_empty(&region)) {
+ struct pixman_box32 *region_box = pixman_region32_extents(&region);
+ *box = (struct wlr_box){
+ .x = region_box->x1,
+ .y = region_box->y1,
+ .width = region_box->x2 - region_box->x1,
+ .height = region_box->y2 - region_box->y1,
+ };
+ }
+
+ pixman_region32_fini(&region);
+}
+
struct render_list_entry {
struct wlr_scene_node *node;
bool sent_dmabuf_feedback;
@@ -1198,9 +1312,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
scene_node_get_size(node, &dst_box.width, &dst_box.height);
scale_box(&dst_box, data->scale);
- // Shadow box
- struct wlr_box shadow_box = dst_box;
-
pixman_region32_t opaque;
pixman_region32_init(&opaque);
scene_node_opaque_region(node, x, y, &opaque);
@@ -1231,6 +1342,36 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
};
fx_render_pass_add_rect(data->render_pass, &rect_options);
break;
+ case WLR_SCENE_NODE_SHADOW:;
+ struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node);
+
+ // Look through the first direct sibling node and get the size of the
+ // node. If the sibling is a tree, get the total size of the whole tree.
+ // Cannot grab the first buffer in the tree due to it potentially being
+ // a CSD surface and not the actual toplevel surface.
+ struct wlr_box window_box;
+ int window_corner_radius;
+ scene_get_next_sibling_geometry(node, &window_box, &window_corner_radius);
+
+ transform_output_box(&window_box, data);
+
+ struct fx_render_box_shadow_options shadow_options = {
+ .box = dst_box,
+ // TODO: Use dst_box if larger?
+ .window_box = window_box,
+ .window_corner_radius = window_corner_radius,
+ .blur_sigma = scene_shadow->blur_sigma,
+ .corner_radius = scene_shadow->corner_radius,
+ .color = {
+ .r = scene_shadow->color[0],
+ .g = scene_shadow->color[1],
+ .b = scene_shadow->color[2],
+ .a = scene_shadow->color[3],
+ },
+ .clip = &render_region,
+ };
+ fx_render_pass_add_box_shadow(data->render_pass, &shadow_options);
+ break;
case WLR_SCENE_NODE_BUFFER:;
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
assert(scene_buffer->buffer);
@@ -1245,27 +1386,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
wlr_output_transform_invert(scene_buffer->transform);
transform = wlr_output_transform_compose(transform, data->transform);
- // Shadow
- if (scene_buffer_has_shadow(&scene_buffer->shadow_data)) {
- struct shadow_data shadow_data = scene_buffer->shadow_data;
- shadow_box.x -= shadow_data.blur_sigma - shadow_data.offset_x;
- shadow_box.y -= shadow_data.blur_sigma - shadow_data.offset_y;
- shadow_box.width += shadow_data.blur_sigma * 2;
- shadow_box.height += shadow_data.blur_sigma * 2;
- transform_output_box(&shadow_box, data);
-
- shadow_data.color.a *= scene_buffer->opacity;
-
- struct fx_render_box_shadow_options shadow_options = {
- .shadow_box = shadow_box,
- .clip_box = dst_box,
- .clip = &render_region,
- .shadow_data = &shadow_data,
- .corner_radius = scene_buffer->corner_radius * data->scale,
- };
- fx_render_pass_add_box_shadow(data->render_pass, &shadow_options);
- }
-
struct fx_render_texture_options tex_options = {
.base = (struct wlr_render_texture_options){
.texture = texture,
@@ -1512,6 +1632,10 @@ static bool scene_node_invisible(struct wlr_scene_node *node) {
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
return rect->color[3] == 0.f;
+ } else if (node->type == WLR_SCENE_NODE_SHADOW) {
+ struct wlr_scene_shadow *shadow = wlr_scene_shadow_from_node(node);
+
+ return shadow->color[3] == 0.f;
} else if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);