Merge pull request #1756 from emersion/output-damage

Fine-grained damage tracking
This commit is contained in:
Drew DeVault 2018-04-07 11:53:10 -04:00 committed by GitHub
commit c47b4d4edb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 339 additions and 269 deletions

View file

@ -1,7 +1,4 @@
#include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_surface.h>
void desktop_damage_whole_surface(struct wlr_surface *surface, double lx, void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
double ly); bool whole);
void desktop_damage_from_surface(struct wlr_surface *surface, double lx,
double ly);

View file

@ -34,11 +34,11 @@ struct sway_output {
void output_damage_whole(struct sway_output *output); void output_damage_whole(struct sway_output *output);
void output_damage_whole_surface(struct sway_output *output, void output_damage_surface(struct sway_output *output, double ox, double oy,
double ox, double oy, struct wlr_surface *surface); struct wlr_surface *surface, bool whole);
void output_damage_whole_view(struct sway_output *output, void output_damage_view(struct sway_output *output, struct sway_view *view,
struct sway_view *view); bool whole);
void output_damage_whole_container(struct sway_output *output, void output_damage_whole_container(struct sway_output *output,
struct sway_container *con); struct sway_container *con);

View file

@ -157,9 +157,7 @@ void view_set_activated(struct sway_view *view, bool activated);
void view_close(struct sway_view *view); void view_close(struct sway_view *view);
void view_damage_whole(struct sway_view *view); void view_damage(struct sway_view *view, bool whole);
void view_damage_from(struct sway_view *view);
void view_for_each_surface(struct sway_view *view, void view_for_each_surface(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data); wlr_surface_iterator_func_t iterator, void *user_data);

View file

@ -30,10 +30,7 @@ struct cmd_results *cmd_opacity(int argc, char **argv) {
} }
con->alpha = opacity; con->alpha = opacity;
container_damage_whole(con);
if (con->type == C_VIEW) {
view_damage_whole(con->sway_view);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }

View file

@ -2,19 +2,13 @@
#include "sway/desktop.h" #include "sway/desktop.h"
#include "sway/output.h" #include "sway/output.h"
void desktop_damage_whole_surface(struct wlr_surface *surface, double lx, void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
double ly) { bool whole) {
for (int i = 0; i < root_container.children->length; ++i) { for (int i = 0; i < root_container.children->length; ++i) {
struct sway_container *cont = root_container.children->items[i]; struct sway_container *cont = root_container.children->items[i];
if (cont->type == C_OUTPUT) { if (cont->type == C_OUTPUT) {
output_damage_whole_surface(cont->sway_output, output_damage_surface(cont->sway_output, lx - cont->x, ly - cont->y,
lx - cont->x, ly - cont->y, surface); surface, whole);
} }
} }
} }
void desktop_damage_from_surface(struct wlr_surface *surface, double lx,
double ly) {
// TODO
desktop_damage_whole_surface(surface, lx, ly);
}

View file

@ -229,33 +229,39 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
wl_container_of(listener, layer, surface_commit); wl_container_of(listener, layer, surface_commit);
struct wlr_layer_surface *layer_surface = layer->layer_surface; struct wlr_layer_surface *layer_surface = layer->layer_surface;
struct wlr_output *wlr_output = layer_surface->output; struct wlr_output *wlr_output = layer_surface->output;
if (wlr_output != NULL) { if (wlr_output == NULL) {
struct sway_output *output = wlr_output->data; return;
struct wlr_box old_geo = layer->geo; }
arrange_layers(output);
if (memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0) { struct sway_output *output = wlr_output->data;
// TODO DAMAGE apply whole surface from previous and new geos struct wlr_box old_geo = layer->geo;
} else { arrange_layers(output);
// TODO DAMAGE from surface damage if (memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0) {
} output_damage_surface(output, old_geo.x, old_geo.y,
wlr_output_damage_add_box(output->damage, &old_geo); layer_surface->surface, true);
wlr_output_damage_add_box(output->damage, &layer->geo); output_damage_surface(output, layer->geo.x, layer->geo.y,
layer_surface->surface, true);
} else {
output_damage_surface(output, layer->geo.x, layer->geo.y,
layer_surface->surface, false);
} }
} }
static void unmap(struct sway_layer_surface *sway_layer) { static void unmap(struct sway_layer_surface *sway_layer) {
struct wlr_output *wlr_output = sway_layer->layer_surface->output; struct wlr_output *wlr_output = sway_layer->layer_surface->output;
if (wlr_output != NULL) { if (wlr_output == NULL) {
struct sway_output *output = wlr_output->data; return;
wlr_output_damage_add_box(output->damage, &sway_layer->geo);
} }
struct sway_output *output = wlr_output->data;
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
sway_layer->layer_surface->surface, true);
} }
static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer = wl_container_of(listener, struct sway_layer_surface *sway_layer =
sway_layer, destroy); wl_container_of(listener, sway_layer, destroy);
wlr_log(L_DEBUG, "Layer surface destroyed (%s)", wlr_log(L_DEBUG, "Layer surface destroyed (%s)",
sway_layer->layer_surface->namespace); sway_layer->layer_surface->namespace);
if (sway_layer->layer_surface->mapped) { if (sway_layer->layer_surface->mapped) {
unmap(sway_layer); unmap(sway_layer);
} }
@ -277,7 +283,9 @@ static void handle_map(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer = wl_container_of(listener, struct sway_layer_surface *sway_layer = wl_container_of(listener,
sway_layer, map); sway_layer, map);
struct sway_output *output = sway_layer->layer_surface->output->data; struct sway_output *output = sway_layer->layer_surface->output->data;
wlr_output_damage_add_box(output->damage, &sway_layer->geo); output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
sway_layer->layer_surface->surface, true);
// TODO: send enter to subsurfaces and popups
wlr_surface_send_enter(sway_layer->layer_surface->surface, wlr_surface_send_enter(sway_layer->layer_surface->surface,
sway_layer->layer_surface->output); sway_layer->layer_surface->output);
} }

View file

@ -1,8 +1,8 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h>
#include <strings.h> #include <strings.h>
#include <time.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_box.h> #include <wlr/types/wlr_box.h>
@ -12,6 +12,7 @@
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_wl_shell.h> #include <wlr/types/wlr_wl_shell.h>
#include <wlr/util/region.h>
#include "log.h" #include "log.h"
#include "sway/input/input-manager.h" #include "sway/input/input-manager.h"
#include "sway/input/seat.h" #include "sway/input/seat.h"
@ -38,191 +39,201 @@ struct sway_container *output_by_name(const char *name) {
*/ */
static void rotate_child_position(double *sx, double *sy, double sw, double sh, static void rotate_child_position(double *sx, double *sy, double sw, double sh,
double pw, double ph, float rotation) { double pw, double ph, float rotation) {
if (rotation != 0.0) { if (rotation == 0.0f) {
// Coordinates relative to the center of the subsurface return;
double ox = *sx - pw/2 + sw/2,
oy = *sy - ph/2 + sh/2;
// Rotated coordinates
double rx = cos(-rotation)*ox - sin(-rotation)*oy,
ry = cos(-rotation)*oy + sin(-rotation)*ox;
*sx = rx + pw/2 - sw/2;
*sy = ry + ph/2 - sh/2;
} }
// Coordinates relative to the center of the subsurface
double ox = *sx - pw/2 + sw/2,
oy = *sy - ph/2 + sh/2;
// Rotated coordinates
double rx = cos(-rotation)*ox - sin(-rotation)*oy,
ry = cos(-rotation)*oy + sin(-rotation)*ox;
*sx = rx + pw/2 - sw/2;
*sy = ry + ph/2 - sh/2;
} }
/** /**
* Checks whether a surface at (lx, ly) intersects an output. If `box` is not * Contains a surface's root geometry information. For instance, when rendering
* NULL, it populates it with the surface box in the output, in output-local * a popup, this will contain the parent view's position and size.
* coordinates.
*/ */
static bool surface_intersect_output(struct wlr_surface *surface, struct root_geometry {
struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, double x, y;
double ox, double oy, float rotation, struct wlr_box *box) { int width, height;
if (box != NULL) { float rotation;
box->x = ox * wlr_output->scale; };
box->y = oy * wlr_output->scale;
box->width = surface->current->width * wlr_output->scale; static bool get_surface_box(struct root_geometry *geo,
box->height = surface->current->height * wlr_output->scale; struct sway_output *output, struct wlr_surface *surface, int sx, int sy,
struct wlr_box *surface_box) {
int sw = surface->current->width;
int sh = surface->current->height;
double _sx = sx, _sy = sy;
rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height,
geo->rotation);
struct wlr_box box = {
.x = geo->x + _sx,
.y = geo->y + _sy,
.width = sw,
.height = sh,
};
if (surface_box != NULL) {
memcpy(surface_box, &box, sizeof(struct wlr_box));
} }
struct wlr_box layout_box = { struct wlr_box rotated_box;
.x = wlr_output->lx + ox, .y = wlr_output->ly + oy, wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box);
.width = surface->current->width, .height = surface->current->height,
struct wlr_box output_box = {
.width = output->swayc->width,
.height = output->swayc->height,
}; };
wlr_box_rotated_bounds(&layout_box, rotation, &layout_box);
return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); struct wlr_box intersection;
return wlr_box_intersection(&output_box, &rotated_box, &intersection);
} }
static void render_surface(struct wlr_surface *surface, static void output_surface_for_each_surface(struct wlr_surface *surface,
struct wlr_output *wlr_output, struct timespec *when, double ox, double oy, struct root_geometry *geo,
double ox, double oy, float rotation, float alpha) { wlr_surface_iterator_func_t iterator, void *user_data) {
struct wlr_renderer *renderer = geo->x = ox;
wlr_backend_get_renderer(wlr_output->backend); geo->y = oy;
geo->width = surface->current->width;
geo->height = surface->current->height;
geo->rotation = 0;
wlr_surface_for_each_surface(surface, iterator, user_data);
}
static void output_view_for_each_surface(struct sway_view *view,
struct root_geometry *geo, wlr_surface_iterator_func_t iterator,
void *user_data) {
geo->x = view->swayc->x;
geo->y = view->swayc->y;
geo->width = view->surface->current->width;
geo->height = view->surface->current->height;
geo->rotation = 0; // TODO
view_for_each_surface(view, iterator, user_data);
}
static void scale_box(struct wlr_box *box, float scale) {
box->x *= scale;
box->y *= scale;
box->width *= scale;
box->height *= scale;
}
struct render_data {
struct root_geometry root_geo;
struct sway_output *output;
struct timespec *when;
float alpha;
};
static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
void *_data) {
struct render_data *data = _data;
struct wlr_output *wlr_output = data->output->wlr_output;
struct timespec *when = data->when;
float rotation = data->root_geo.rotation;
float alpha = data->alpha;
if (!wlr_surface_has_buffer(surface)) { if (!wlr_surface_has_buffer(surface)) {
return; return;
} }
struct wlr_output_layout *layout = root_container.sway_root->output_layout;
struct wlr_box box; struct wlr_box box;
bool intersects = surface_intersect_output(surface, layout, wlr_output, bool intersects = get_surface_box(&data->root_geo, data->output, surface,
ox, oy, rotation, &box); sx, sy, &box);
if (intersects) { if (!intersects) {
float matrix[9]; return;
enum wl_output_transform transform =
wlr_output_transform_invert(surface->current->transform);
wlr_matrix_project_box(matrix, &box, transform, rotation,
wlr_output->transform_matrix);
wlr_render_texture_with_matrix(renderer, surface->texture,
matrix, alpha);
wlr_surface_send_frame_done(surface, when);
} }
struct wlr_subsurface *subsurface; struct wlr_renderer *renderer =
wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { wlr_backend_get_renderer(wlr_output->backend);
struct wlr_surface_state *state = subsurface->surface->current; if (!sway_assert(renderer != NULL,
double sx = state->subsurface_position.x; "expected the output backend to have a renderer")) {
double sy = state->subsurface_position.y; return;
rotate_child_position(&sx, &sy, state->width, state->height, }
surface->current->width, surface->current->height, rotation);
render_surface(subsurface->surface, wlr_output, when, scale_box(&box, wlr_output->scale);
ox + sx, oy + sy, rotation, alpha);
float matrix[9];
enum wl_output_transform transform =
wlr_output_transform_invert(surface->current->transform);
wlr_matrix_project_box(matrix, &box, transform, rotation,
wlr_output->transform_matrix);
wlr_render_texture_with_matrix(renderer, surface->texture,
matrix, alpha);
// TODO: don't send the frame done event now
wlr_surface_send_frame_done(surface, when);
}
static void render_surface(struct sway_output *output, struct timespec *when,
struct wlr_surface *surface, double ox, double oy) {
struct render_data data = {
.output = output,
.when = when,
.alpha = 1.0f,
};
output_surface_for_each_surface(surface, ox, oy, &data.root_geo,
render_surface_iterator, &data);
}
static void render_view(struct sway_output *output, struct timespec *when,
struct sway_view *view) {
struct render_data data = {
.output = output,
.when = when,
.alpha = view->swayc->alpha,
};
output_view_for_each_surface(view, &data.root_geo,
render_surface_iterator, &data);
}
static void render_layer(struct sway_output *output, struct timespec *when,
struct wl_list *layer_surfaces) {
struct sway_layer_surface *layer_surface;
wl_list_for_each(layer_surface, layer_surfaces, link) {
struct wlr_layer_surface *wlr_layer_surface =
layer_surface->layer_surface;
render_surface(output, when, wlr_layer_surface->surface,
layer_surface->geo.x, layer_surface->geo.y);
} }
} }
static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, struct render_view_data {
struct wlr_output *wlr_output, struct timespec *when, double base_x,
double base_y, float rotation, float alpha) {
double width = surface->surface->current->width;
double height = surface->surface->current->height;
struct wlr_xdg_popup_v6 *popup_state;
wl_list_for_each(popup_state, &surface->popups, link) {
struct wlr_xdg_surface_v6 *popup = popup_state->base;
if (!popup->configured) {
continue;
}
double popup_width = popup->surface->current->width;
double popup_height = popup->surface->current->height;
double popup_sx, popup_sy;
wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy);
rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height,
width, height, rotation);
render_surface(popup->surface, wlr_output, when,
base_x + popup_sx, base_y + popup_sy, rotation, alpha);
render_xdg_v6_popups(popup, wlr_output, when,
base_x + popup_sx, base_y + popup_sy, rotation, alpha);
}
}
static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface,
struct wlr_output *wlr_output, struct timespec *when,
double lx, double ly, float rotation, float alpha,
bool is_child) {
if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) {
render_surface(surface->surface, wlr_output, when,
lx, ly, rotation, alpha);
double width = surface->surface->current->width;
double height = surface->surface->current->height;
struct wlr_wl_shell_surface *popup;
wl_list_for_each(popup, &surface->popups, popup_link) {
double popup_width = popup->surface->current->width;
double popup_height = popup->surface->current->height;
double popup_x = popup->transient_state->x;
double popup_y = popup->transient_state->y;
rotate_child_position(&popup_x, &popup_y, popup_width, popup_height,
width, height, rotation);
render_wl_shell_surface(popup, wlr_output, when,
lx + popup_x, ly + popup_y, rotation, alpha, true);
}
}
}
struct render_data {
struct sway_output *output; struct sway_output *output;
struct timespec *when; struct timespec *when;
}; };
static void render_view(struct sway_container *view, void *data) { static void render_view_iterator(struct sway_container *con, void *_data) {
struct render_data *rdata = data; struct render_view_data *data = _data;
struct sway_output *output = rdata->output;
struct timespec *when = rdata->when;
struct wlr_output *wlr_output = output->wlr_output;
struct sway_view *sway_view = view->sway_view;
struct wlr_surface *surface = sway_view->surface;
float alpha = sway_view->swayc->alpha;
if (!surface) { if (!sway_assert(con->type == C_VIEW, "expected a view")) {
return; return;
} }
switch (sway_view->type) { render_view(data->output, data->when, con->sway_view);
case SWAY_VIEW_XDG_SHELL_V6: {
int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x;
int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y;
render_surface(surface, wlr_output, when,
view->x - window_offset_x, view->y - window_offset_y, 0, alpha);
render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output,
when, view->x - window_offset_x, view->y - window_offset_y, 0, alpha);
break;
}
case SWAY_VIEW_WL_SHELL:
render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output,
when, view->x, view->y, 0, alpha, false);
break;
case SWAY_VIEW_XWAYLAND:
render_surface(surface, wlr_output, when, view->x, view->y, 0, alpha);
break;
}
}
static void render_layer(struct sway_output *output, struct timespec *when,
struct wl_list *layer) {
struct sway_layer_surface *sway_layer;
wl_list_for_each(sway_layer, layer, link) {
struct wlr_layer_surface *layer = sway_layer->layer_surface;
render_surface(layer->surface, output->wlr_output, when,
sway_layer->geo.x, sway_layer->geo.y, 0, 1.0f);
wlr_surface_send_frame_done(layer->surface, when);
}
} }
static void render_output(struct sway_output *output, struct timespec *when, static void render_output(struct sway_output *output, struct timespec *when,
pixman_region32_t *damage) { pixman_region32_t *damage) {
struct wlr_output *wlr_output = output->wlr_output; struct wlr_output *wlr_output = output->wlr_output;
struct wlr_renderer *renderer = struct wlr_renderer *renderer =
wlr_backend_get_renderer(wlr_output->backend); wlr_backend_get_renderer(wlr_output->backend);
if (!sway_assert(renderer != NULL,
"expected the output backend to have a renderer")) {
return;
}
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
@ -231,7 +242,7 @@ static void render_output(struct sway_output *output, struct timespec *when,
goto renderer_end; goto renderer_end;
} }
// TODO: don't damage the whole output here // TODO: don't damage the whole output
int width, height; int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height); wlr_output_transformed_resolution(wlr_output, &width, &height);
pixman_region32_union_rect(damage, damage, 0, 0, width, height); pixman_region32_union_rect(damage, damage, 0, 0, width, height);
@ -239,16 +250,12 @@ static void render_output(struct sway_output *output, struct timespec *when,
float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
wlr_renderer_clear(renderer, clear_color); wlr_renderer_clear(renderer, clear_color);
struct wlr_output_layout *output_layout =
root_container.sway_root->output_layout;
const struct wlr_box *output_box =
wlr_output_layout_get_box(output_layout, wlr_output);
render_layer(output, when, render_layer(output, when,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
render_layer(output, when, render_layer(output, when,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
// Render all views in the current workspace
struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus = struct sway_container *focus =
seat_get_focus_inactive(seat, output->swayc); seat_get_focus_inactive(seat, output->swayc);
@ -258,36 +265,21 @@ static void render_output(struct sway_output *output, struct timespec *when,
} }
struct sway_container *workspace = focus->type == C_WORKSPACE ? struct sway_container *workspace = focus->type == C_WORKSPACE ?
focus : container_parent(focus, C_WORKSPACE); focus : container_parent(focus, C_WORKSPACE);
struct render_view_data data = { .output = output, .when = when };
container_descendants(workspace, C_VIEW, render_view_iterator, &data);
struct render_data rdata = { // Render unmanaged views on top
.output = output,
.when = when,
};
container_descendants(workspace, C_VIEW, render_view, &rdata);
// render unmanaged views on top
struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
struct sway_xwayland_unmanaged *unmanaged_surface; struct sway_xwayland_unmanaged *unmanaged_surface;
wl_list_for_each(unmanaged_surface, unmanaged, link) { wl_list_for_each(unmanaged_surface, unmanaged, link) {
struct wlr_xwayland_surface *xsurface = struct wlr_xwayland_surface *xsurface =
unmanaged_surface->wlr_xwayland_surface; unmanaged_surface->wlr_xwayland_surface;
double ox = unmanaged_surface->lx - output->swayc->x;
const struct wlr_box view_box = { double oy = unmanaged_surface->ly - output->swayc->y;
.x = unmanaged_surface->lx, render_surface(output, when, xsurface->surface, ox, oy);
.y = unmanaged_surface->ly,
.width = xsurface->width,
.height = xsurface->height,
};
struct wlr_box intersection;
if (!wlr_box_intersection(&view_box, output_box, &intersection)) {
continue;
}
render_surface(xsurface->surface, wlr_output, &output->last_frame,
view_box.x - output_box->x, view_box.y - output_box->y, 0, 1.0f);
} }
// TODO: Consider revising this when fullscreen windows are supported // TODO: consider revising this when fullscreen windows are supported
render_layer(output, when, render_layer(output, when,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
render_layer(output, when, render_layer(output, when,
@ -337,22 +329,107 @@ void output_damage_whole(struct sway_output *output) {
wlr_output_damage_add_whole(output->damage); wlr_output_damage_add_whole(output->damage);
} }
void output_damage_whole_surface(struct sway_output *output, struct damage_data {
double ox, double oy, struct wlr_surface *surface) { struct root_geometry root_geo;
// TODO struct sway_output *output;
output_damage_whole(output); bool whole;
};
static void damage_surface_iterator(struct wlr_surface *surface, int sx, int sy,
void *_data) {
struct damage_data *data = _data;
struct sway_output *output = data->output;
float rotation = data->root_geo.rotation;
bool whole = data->whole;
if (!wlr_surface_has_buffer(surface)) {
return;
}
struct wlr_box box;
bool intersects = get_surface_box(&data->root_geo, data->output, surface,
sx, sy, &box);
if (!intersects) {
return;
}
scale_box(&box, output->wlr_output->scale);
if (whole) {
wlr_box_rotated_bounds(&box, rotation, &box);
wlr_output_damage_add_box(output->damage, &box);
} else {
int center_x = box.x + box.width/2;
int center_y = box.y + box.height/2;
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_copy(&damage, &surface->current->surface_damage);
wlr_region_scale(&damage, &damage, output->wlr_output->scale);
if (ceil(output->wlr_output->scale) > surface->current->scale) {
// When scaling up a surface, it'll become blurry so we need to
// expand the damage region
wlr_region_expand(&damage, &damage,
ceil(output->wlr_output->scale) - surface->current->scale);
}
pixman_region32_translate(&damage, box.x, box.y);
wlr_region_rotated_bounds(&damage, &damage, rotation,
center_x, center_y);
wlr_output_damage_add(output->damage, &damage);
pixman_region32_fini(&damage);
}
} }
void output_damage_whole_view(struct sway_output *output, void output_damage_surface(struct sway_output *output, double ox, double oy,
struct sway_view *view) { struct wlr_surface *surface, bool whole) {
// TODO struct damage_data data = {
output_damage_whole(output); .output = output,
.whole = whole,
};
output_surface_for_each_surface(surface, ox, oy, &data.root_geo,
damage_surface_iterator, &data);
}
void output_damage_view(struct sway_output *output, struct sway_view *view,
bool whole) {
if (!sway_assert(view->swayc != NULL, "expected a view in the tree")) {
return;
}
struct damage_data data = {
.output = output,
.whole = whole,
};
output_view_for_each_surface(view, &data.root_geo,
damage_surface_iterator, &data);
}
static void output_damage_whole_container_iterator(struct sway_container *con,
void *data) {
struct sway_output *output = data;
if (!sway_assert(con->type != C_VIEW, "expected a view")) {
return;
}
output_damage_view(output, con->sway_view, true);
} }
void output_damage_whole_container(struct sway_output *output, void output_damage_whole_container(struct sway_output *output,
struct sway_container *con) { struct sway_container *con) {
// TODO float scale = output->wlr_output->scale;
output_damage_whole(output); struct wlr_box box = {
.x = con->x * scale,
.y = con->y * scale,
.width = con->width * scale,
.height = con->height * scale,
};
wlr_output_damage_add_box(output->damage, &box);
container_descendants(con, C_VIEW, output_damage_whole_container_iterator,
output);
} }
static void damage_handle_destroy(struct wl_listener *listener, void *data) { static void damage_handle_destroy(struct wl_listener *listener, void *data) {

View file

@ -79,7 +79,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
// TODO: Let floating views do whatever // TODO: Let floating views do whatever
view_update_size(view, wl_shell_view->pending_width, view_update_size(view, wl_shell_view->pending_width,
wl_shell_view->pending_height); wl_shell_view->pending_height);
view_damage_from(view); view_damage(view, false);
} }
static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) {

View file

@ -143,9 +143,7 @@ static void destroy(struct sway_view *view) {
if (xdg_shell_v6_view == NULL) { if (xdg_shell_v6_view == NULL) {
return; return;
} }
wl_list_remove(&xdg_shell_v6_view->commit.link);
wl_list_remove(&xdg_shell_v6_view->destroy.link); wl_list_remove(&xdg_shell_v6_view->destroy.link);
wl_list_remove(&xdg_shell_v6_view->new_popup.link);
wl_list_remove(&xdg_shell_v6_view->map.link); wl_list_remove(&xdg_shell_v6_view->map.link);
wl_list_remove(&xdg_shell_v6_view->unmap.link); wl_list_remove(&xdg_shell_v6_view->unmap.link);
free(xdg_shell_v6_view); free(xdg_shell_v6_view);
@ -169,7 +167,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
// TODO: Let floating views do whatever // TODO: Let floating views do whatever
view_update_size(view, xdg_shell_v6_view->pending_width, view_update_size(view, xdg_shell_v6_view->pending_width,
xdg_shell_v6_view->pending_height); xdg_shell_v6_view->pending_height);
view_damage_from(view); view_damage(view, false);
} }
static void handle_new_popup(struct wl_listener *listener, void *data) { static void handle_new_popup(struct wl_listener *listener, void *data) {
@ -182,14 +180,28 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
static void handle_unmap(struct wl_listener *listener, void *data) { static void handle_unmap(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_v6_view *xdg_shell_v6_view = struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
wl_container_of(listener, xdg_shell_v6_view, unmap); wl_container_of(listener, xdg_shell_v6_view, unmap);
view_unmap(&xdg_shell_v6_view->view); view_unmap(&xdg_shell_v6_view->view);
wl_list_remove(&xdg_shell_v6_view->commit.link);
wl_list_remove(&xdg_shell_v6_view->new_popup.link);
} }
static void handle_map(struct wl_listener *listener, void *data) { static void handle_map(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_v6_view *xdg_shell_v6_view = struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
wl_container_of(listener, xdg_shell_v6_view, map); wl_container_of(listener, xdg_shell_v6_view, map);
struct sway_view *view = &xdg_shell_v6_view->view; struct sway_view *view = &xdg_shell_v6_view->view;
struct wlr_xdg_surface_v6 *xdg_surface = view->wlr_xdg_surface_v6;
view_map(view, view->wlr_xdg_surface_v6->surface); view_map(view, view->wlr_xdg_surface_v6->surface);
xdg_shell_v6_view->commit.notify = handle_commit;
wl_signal_add(&xdg_surface->surface->events.commit,
&xdg_shell_v6_view->commit);
xdg_shell_v6_view->new_popup.notify = handle_new_popup;
wl_signal_add(&xdg_surface->events.new_popup,
&xdg_shell_v6_view->new_popup);
} }
static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) {
@ -226,14 +238,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
// - Look up pid and open on appropriate workspace // - Look up pid and open on appropriate workspace
// - Criteria // - Criteria
xdg_shell_v6_view->commit.notify = handle_commit;
wl_signal_add(&xdg_surface->surface->events.commit,
&xdg_shell_v6_view->commit);
xdg_shell_v6_view->new_popup.notify = handle_new_popup;
wl_signal_add(&xdg_surface->events.new_popup,
&xdg_shell_v6_view->new_popup);
xdg_shell_v6_view->map.notify = handle_map; xdg_shell_v6_view->map.notify = handle_map;
wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map); wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map);

View file

@ -32,15 +32,15 @@ static void unmanaged_handle_commit(struct wl_listener *listener, void *data) {
if (xsurface->x != surface->lx || xsurface->y != surface->ly) { if (xsurface->x != surface->lx || xsurface->y != surface->ly) {
// Surface has moved // Surface has moved
desktop_damage_whole_surface(xsurface->surface, desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
surface->lx, surface->ly); true);
surface->lx = xsurface->x; surface->lx = xsurface->x;
surface->ly = xsurface->y; surface->ly = xsurface->y;
desktop_damage_whole_surface(xsurface->surface, desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
surface->lx, surface->ly); true);
} else { } else {
desktop_damage_from_surface(xsurface->surface, desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y,
xsurface->x, xsurface->y); false);
} }
} }
@ -57,7 +57,7 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
surface->lx = xsurface->x; surface->lx = xsurface->x;
surface->ly = xsurface->y; surface->ly = xsurface->y;
desktop_damage_whole_surface(xsurface->surface, surface->lx, surface->ly); desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true);
// TODO: we don't send surface enter/leave events to xwayland unmanaged // TODO: we don't send surface enter/leave events to xwayland unmanaged
// surfaces, but xwayland doesn't support HiDPI anyway // surfaces, but xwayland doesn't support HiDPI anyway
@ -67,7 +67,7 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface = struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, unmap); wl_container_of(listener, surface, unmap);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
desktop_damage_whole_surface(xsurface->surface, xsurface->x, xsurface->y); desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true);
wl_list_remove(&surface->link); wl_list_remove(&surface->link);
wl_list_remove(&surface->commit.link); wl_list_remove(&surface->commit.link);
} }
@ -209,7 +209,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
// TODO: Let floating views do whatever // TODO: Let floating views do whatever
view_update_size(view, xwayland_view->pending_width, view_update_size(view, xwayland_view->pending_width,
xwayland_view->pending_height); xwayland_view->pending_height);
view_damage_from(view); view_damage(view, false);
} }
static void handle_unmap(struct wl_listener *listener, void *data) { static void handle_unmap(struct wl_listener *listener, void *data) {

View file

@ -79,20 +79,15 @@ void view_close(struct sway_view *view) {
} }
} }
void view_damage_whole(struct sway_view *view) { void view_damage(struct sway_view *view, bool whole) {
for (int i = 0; i < root_container.children->length; ++i) { for (int i = 0; i < root_container.children->length; ++i) {
struct sway_container *cont = root_container.children->items[i]; struct sway_container *cont = root_container.children->items[i];
if (cont->type == C_OUTPUT) { if (cont->type == C_OUTPUT) {
output_damage_whole_view(cont->sway_output, view); output_damage_view(cont->sway_output, view, whole);
} }
} }
} }
void view_damage_from(struct sway_view *view) {
// TODO
view_damage_whole(view);
}
static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) {
struct sway_container *output = container_parent(view->swayc, C_OUTPUT); struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
@ -191,7 +186,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
arrange_windows(cont->parent, -1, -1); arrange_windows(cont->parent, -1, -1);
input_manager_set_focus(input_manager, cont); input_manager_set_focus(input_manager, cont);
view_damage_whole(view); view_damage(view, true);
view_handle_container_reparent(&view->container_reparent, NULL); view_handle_container_reparent(&view->container_reparent, NULL);
} }
@ -202,7 +197,7 @@ void view_unmap(struct sway_view *view) {
wl_signal_emit(&view->events.unmap, view); wl_signal_emit(&view->events.unmap, view);
view_damage_whole(view); view_damage(view, true);
wl_list_remove(&view->surface_new_subsurface.link); wl_list_remove(&view->surface_new_subsurface.link);
wl_list_remove(&view->container_reparent.link); wl_list_remove(&view->container_reparent.link);
@ -220,10 +215,10 @@ void view_update_position(struct sway_view *view, double ox, double oy) {
return; return;
} }
view_damage_whole(view); view_damage(view, true);
view->swayc->x = ox; view->swayc->x = ox;
view->swayc->y = oy; view->swayc->y = oy;
view_damage_whole(view); view_damage(view, true);
} }
void view_update_size(struct sway_view *view, int width, int height) { void view_update_size(struct sway_view *view, int width, int height) {
@ -231,10 +226,10 @@ void view_update_size(struct sway_view *view, int width, int height) {
return; return;
} }
view_damage_whole(view); view_damage(view, true);
view->width = width; view->width = width;
view->height = height; view->height = height;
view_damage_whole(view); view_damage(view, true);
} }
@ -253,7 +248,7 @@ static void view_child_handle_surface_commit(struct wl_listener *listener,
struct sway_view_child *child = struct sway_view_child *child =
wl_container_of(listener, child, surface_commit); wl_container_of(listener, child, surface_commit);
// TODO: only accumulate damage from the child // TODO: only accumulate damage from the child
view_damage_from(child->view); view_damage(child->view, false);
} }
static void view_child_handle_surface_new_subsurface( static void view_child_handle_surface_new_subsurface(
@ -315,12 +310,12 @@ void view_child_init(struct sway_view_child *child,
view_init_subsurfaces(child->view, surface); view_init_subsurfaces(child->view, surface);
// TODO: only damage the whole child // TODO: only damage the whole child
view_damage_whole(child->view); view_damage(child->view, true);
} }
void view_child_destroy(struct sway_view_child *child) { void view_child_destroy(struct sway_view_child *child) {
// TODO: only damage the whole child // TODO: only damage the whole child
view_damage_whole(child->view); view_damage(child->view, true);
wl_list_remove(&child->surface_commit.link); wl_list_remove(&child->surface_commit.link);
wl_list_remove(&child->surface_destroy.link); wl_list_remove(&child->surface_destroy.link);