aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/types/wlr_scene.h2
-rw-r--r--include/wlr/types/wlr_scene.h2
-rw-r--r--types/scene/surface.c72
3 files changed, 72 insertions, 4 deletions
diff --git a/include/types/wlr_scene.h b/include/types/wlr_scene.h
index 64c11bc6..80dcfd1b 100644
--- a/include/types/wlr_scene.h
+++ b/include/types/wlr_scene.h
@@ -5,4 +5,6 @@
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
+void scene_surface_set_clip(struct wlr_scene_surface *surface, struct wlr_box *clip);
+
#endif
diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
index bb5f025d..3a3d34c2 100644
--- a/include/wlr/types/wlr_scene.h
+++ b/include/wlr/types/wlr_scene.h
@@ -119,6 +119,8 @@ struct wlr_scene_surface {
// private state
+ struct wlr_box clip;
+
struct wlr_addon addon;
struct wl_listener outputs_update;
diff --git a/types/scene/surface.c b/types/scene/surface.c
index e03c3544..b9f52211 100644
--- a/types/scene/surface.c
+++ b/types/scene/surface.c
@@ -100,18 +100,63 @@ static void scene_buffer_unmark_client_buffer(struct wlr_scene_buffer *scene_buf
buffer->n_ignore_locks--;
}
+static int min(int a, int b) {
+ return a < b ? a : b;
+}
+
static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
struct wlr_scene_buffer *scene_buffer = scene_surface->buffer;
struct wlr_surface *surface = scene_surface->surface;
struct wlr_surface_state *state = &surface->current;
- wlr_scene_buffer_set_opaque_region(scene_buffer, &surface->opaque_region);
-
struct wlr_fbox src_box;
wlr_surface_get_buffer_source_box(surface, &src_box);
- wlr_scene_buffer_set_source_box(scene_buffer, &src_box);
- wlr_scene_buffer_set_dest_size(scene_buffer, state->width, state->height);
+ pixman_region32_t opaque;
+ pixman_region32_init(&opaque);
+ pixman_region32_copy(&opaque, &surface->opaque_region);
+
+ int width = state->width;
+ int height = state->height;
+
+ if (!wlr_box_empty(&scene_surface->clip)) {
+ struct wlr_box *clip = &scene_surface->clip;
+
+ int buffer_width = state->buffer_width;
+ int buffer_height = state->buffer_height;
+ width = min(clip->width, width - clip->x);
+ height = min(clip->height, height - clip->y);
+
+ wlr_fbox_transform(&src_box, &src_box, state->transform,
+ buffer_width, buffer_height);
+
+ if (state->transform & WL_OUTPUT_TRANSFORM_90) {
+ int tmp = buffer_width;
+ buffer_width = buffer_height;
+ buffer_height = tmp;
+ }
+
+ src_box.x += (double)(clip->x * buffer_width) / state->width;
+ src_box.y += (double)(clip->y * buffer_height) / state->height;
+ src_box.width *= (double)width / state->width;
+ src_box.height *= (double)height / state->height;
+
+ wlr_fbox_transform(&src_box, &src_box, wlr_output_transform_invert(state->transform),
+ buffer_width, buffer_height);
+
+ pixman_region32_translate(&opaque, -clip->x, -clip->y);
+ pixman_region32_intersect_rect(&opaque, &opaque, 0, 0, width, height);
+ }
+
+ if (width <= 0 || height <= 0) {
+ wlr_scene_buffer_set_buffer(scene_buffer, NULL);
+ pixman_region32_fini(&opaque);
+ return;
+ }
+
+ wlr_scene_buffer_set_opaque_region(scene_buffer, &opaque);
+ wlr_scene_buffer_set_source_box(scene_buffer, &src_box);
+ wlr_scene_buffer_set_dest_size(scene_buffer, width, height);
wlr_scene_buffer_set_transform(scene_buffer, state->transform);
scene_buffer_unmark_client_buffer(scene_buffer);
@@ -124,6 +169,8 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
} else {
wlr_scene_buffer_set_buffer(scene_buffer, NULL);
}
+
+ pixman_region32_fini(&opaque);
}
static void handle_scene_surface_surface_commit(
@@ -153,6 +200,9 @@ static bool scene_buffer_point_accepts_input(struct wlr_scene_buffer *scene_buff
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_try_from_buffer(scene_buffer);
+ *sx += scene_surface->clip.x;
+ *sy += scene_surface->clip.y;
+
return wlr_surface_point_accepts_input(scene_surface->surface, *sx, *sy);
}
@@ -236,3 +286,17 @@ struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent
return surface;
}
+
+void scene_surface_set_clip(struct wlr_scene_surface *surface, struct wlr_box *clip) {
+ if (wlr_box_equal(clip, &surface->clip)) {
+ return;
+ }
+
+ if (clip) {
+ surface->clip = *clip;
+ } else {
+ surface->clip = (struct wlr_box){0};
+ }
+
+ surface_reconfigure(surface);
+}