From 54804fd3df68e51f280c8c00f38bd017f5dedcef Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Sat, 9 Jan 2021 22:51:20 +0000 Subject: [PATCH] Implement damage tracking --- README.md | 6 +- include/labwc.h | 27 +- meson.build | 3 +- src/action.c | 2 + src/cursor.c | 8 +- src/damage.c | 32 ++ src/desktop.c | 1 + src/keyboard.c | 1 + src/layers.c | 2 + src/meson.build | 1 + src/output.c | 909 +++++++++++++++++++++++++++------------ src/view.c | 10 + src/xdg.c | 96 +++++ src/xwayland-unmanaged.c | 4 +- src/xwayland.c | 10 + 15 files changed, 836 insertions(+), 276 deletions(-) create mode 100644 src/damage.c diff --git a/README.md b/README.md index 51f67fdb..ee13705c 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ The following were considered before choosing wlroots: [qtwayland](https://githu Dependencies include: - meson, ninja -- wlroots (>=0.11.0) +- wlroots (0.11.0 - 0.12.0) - wayland (>=1.16) - wayland-protocols - xwayland, xcb (optional) @@ -95,8 +95,8 @@ No acceptance criteria exists, but the following list indicates the inteded high - [x] Show maximize, iconify, close buttons - [x] Catch SIGHUP to re-load config file and theme - [x] Support layer-shell protocol ('exclusive' not yet implemented) -- [ ] Support root-menu and parse menu.xml (very simple implementation, not submenus yet) -- [ ] Support damage tracking to reduce CPU usage +- [x] Support damage tracking to reduce CPU usage +- [ ] Support root-menu and parse menu.xml (very simple implementation, no submenus yet) - [ ] Support 'maximize' - [ ] Support wlr-output-management protocol and [kanshi](https://github.com/emersion/kanshi.git) - [ ] Support foreign-toplevel protocol (e.g. to integrate with wlroots panels/bars) diff --git a/include/labwc.h b/include/labwc.h index b1932ba2..4829e0bc 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -123,9 +124,11 @@ struct output { struct wl_list link; struct server *server; struct wlr_output *wlr_output; + struct wlr_output_damage *damage; struct wl_list layers[4]; - struct wl_listener frame; struct wl_listener destroy; + struct wl_listener damage_frame; + struct wl_listener damage_destroy; }; enum view_type { @@ -151,6 +154,8 @@ enum deco_part { struct view_impl { void (*configure)(struct view *view, struct wlr_box geo); void (*close)(struct view *view); + void (*for_each_popup)(struct view *view, + wlr_surface_iterator_func_t iterator, void *data); void (*for_each_surface)(struct view *view, wlr_surface_iterator_func_t iterator, void *data); void (*map)(struct view *view); @@ -211,6 +216,7 @@ struct view { struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_configure; + struct wl_listener new_popup; /* xdg-shell only */ }; #if HAVE_XWAYLAND @@ -228,6 +234,17 @@ struct xwayland_unmanaged { }; #endif +struct xdg_popup { + struct wlr_xdg_popup *wlr_popup; + struct view *view; + + struct wl_listener destroy; + struct wl_listener commit; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener new_popup; +}; + void xdg_toplevel_decoration(struct wl_listener *listener, void *data); void xdg_surface_new(struct wl_listener *listener, void *data); @@ -243,6 +260,8 @@ void view_minimize(struct view *view); void view_unminimize(struct view *view); void view_for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, void *user_data); +void view_for_each_popup(struct view *view, + wlr_surface_iterator_func_t iterator, void *data); void desktop_focus_view(struct seat *seat, struct view *view); @@ -270,6 +289,12 @@ void interactive_begin(struct view *view, enum input_mode mode, uint32_t edges); void output_init(struct server *server); +void output_damage_surface(struct output *output, struct wlr_surface *surface, + double lx, double ly, bool whole); + +void damage_all_outputs(struct server *server); +void damage_view_whole(struct view *view); +void damage_view_part(struct view *view); void server_init(struct server *server); void server_start(struct server *server); diff --git a/meson.build b/meson.build index 10776feb..8c3509f2 100644 --- a/meson.build +++ b/meson.build @@ -49,6 +49,7 @@ glib = dependency('glib-2.0') cairo = dependency('cairo') pangocairo = dependency('pangocairo') input = dependency('libinput', version: '>=1.14') +pixman = dependency('pixman-1') if get_option('xwayland').enabled() and not wlroots_has_xwayland error('no wlroots Xwayland support') @@ -63,7 +64,7 @@ subdir('protocols') labwc_deps = [ server_protos, wayland_server, wlroots, xkbcommon, xml2, glib, - cairo, pangocairo, input + cairo, pangocairo, input, pixman ] subdir('include') diff --git a/src/action.c b/src/action.c index 5d37653e..5510dc85 100644 --- a/src/action.c +++ b/src/action.c @@ -15,6 +15,7 @@ show_menu(struct server *server, const char *menu) menu_move(server->rootmenu, server->seat.cursor->x, server->seat.cursor->y); } + damage_all_outputs(server); } void @@ -29,6 +30,7 @@ action(struct server *server, const char *action, const char *command) } else if (!strcasecmp(action, "Exit")) { wl_display_terminate(server->wl_display); } else if (!strcasecmp(action, "NextWindow")) { + dbg_show_views(server); server->cycle_view = desktop_cycle_view(server, server->cycle_view); } else if (!strcasecmp(action, "Reconfigure")) { diff --git a/src/cursor.c b/src/cursor.c index 40ff39e9..7adfed4d 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -66,6 +66,7 @@ request_set_selection_notify(struct wl_listener *listener, void *data) static void process_cursor_move(struct server *server, uint32_t time) { + damage_all_outputs(server); /* Move the grabbed view to the new position. */ double dx = server->seat.cursor->x - server->grab_x; double dy = server->seat.cursor->y - server->grab_y; @@ -81,10 +82,7 @@ process_cursor_move(struct server *server, uint32_t time) static void process_cursor_resize(struct server *server, uint32_t time) { - /* - * TODO: Wait for the client to prepare a buffer at the new size, then - * commit any movement that was prepared. - */ + damage_all_outputs(server); double dx = server->seat.cursor->x - server->grab_x; double dy = server->seat.cursor->y - server->grab_y; @@ -128,6 +126,7 @@ process_cursor_motion(struct server *server, uint32_t time) } else if (server->input_mode == LAB_INPUT_STATE_MENU) { menu_set_selected(server->rootmenu, server->seat.cursor->x, server->seat.cursor->y); + damage_all_outputs(server); return; } @@ -285,6 +284,7 @@ cursor_button(struct wl_listener *listener, void *data) } /* Exit interactive move/resize/menu mode. */ server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; + damage_all_outputs(server); return; } diff --git a/src/damage.c b/src/damage.c new file mode 100644 index 00000000..49d97962 --- /dev/null +++ b/src/damage.c @@ -0,0 +1,32 @@ +#include "labwc.h" + +void +damage_all_outputs(struct server *server) +{ + struct output *output; + wl_list_for_each(output, &server->outputs, link) { + if (output && output->wlr_output && output->damage) { + wlr_output_damage_add_whole(output->damage); + } + } +} + +void +damage_view_part(struct view *view) +{ + struct output *output; + wl_list_for_each (output, &view->server->outputs, link) { + output_damage_surface(output, view->surface, view->x, view->y, + false); + } +} + +void +damage_view_whole(struct view *view) +{ + struct output *output; + wl_list_for_each (output, &view->server->outputs, link) { + output_damage_surface(output, view->surface, view->x, view->y, + true); + } +} diff --git a/src/desktop.c b/src/desktop.c index 534966a0..6a7bf2bc 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -148,6 +148,7 @@ desktop_cycle_view(struct server *server, struct view *current) do { view = wl_container_of(view->link.next, view, link); } while (&view->link == &server->views || !isfocusable(view)); + damage_all_outputs(server); return view; } diff --git a/src/keyboard.c b/src/keyboard.c index 267d7fca..3c90950f 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -49,6 +49,7 @@ keyboard_key_notify(struct wl_listener *listener, void *data) wlr_keyboard_get_modifiers(device->keyboard); if (server->cycle_view) { + damage_all_outputs(server); if ((syms[0] == XKB_KEY_Alt_L) && event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { /* end cycle */ diff --git a/src/layers.c b/src/layers.c index 5041e4b1..d7651e78 100644 --- a/src/layers.c +++ b/src/layers.c @@ -258,6 +258,7 @@ surface_commit_notify(struct wl_listener *listener, void *data) wl_container_of(listener, layer, surface_commit); struct wlr_output *wlr_output = layer->layer_surface->output; arrange_layers(output_from_wlr_output(layer->server, wlr_output)); + damage_all_outputs(layer->server); } static void @@ -267,6 +268,7 @@ unmap(struct lab_layer_surface *layer) if (seat->focused_layer == layer->layer_surface) { seat_set_focus_layer(seat, NULL); } + damage_all_outputs(layer->server); } static void diff --git a/src/meson.build b/src/meson.build index 72518756..a2199971 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,6 +1,7 @@ labwc_sources = files( 'action.c', 'cursor.c', + 'damage.c', 'deco.c', 'desktop.c', 'interactive.c', diff --git a/src/output.c b/src/output.c index 99cec377..d4b99534 100644 --- a/src/output.c +++ b/src/output.c @@ -1,49 +1,357 @@ +/* + * output.c: labwc output and rendering + * + * Copyright (C) 2019-2021 Johan Malm + * Copyright (C) 2020 The Sway authors + */ + #define _POSIX_C_SOURCE 200809L #include "config.h" #include +#include +#include #include "labwc.h" #include "menu/menu.h" #include "theme/theme.h" #include "layers.h" -struct draw_data { - struct wlr_output *output; - struct wlr_output_layout *output_layout; - struct wlr_renderer *renderer; - float *transform_matrix; - float *rgba; +//#define DEBUG 1 + +typedef void (*surface_iterator_func_t)(struct output *output, + struct wlr_surface *surface, struct wlr_box *box, + void *user_data); + +struct surface_iterator_data { + surface_iterator_func_t user_iterator; + void *user_data; + struct output *output; + double ox, oy; }; +static bool +intersects_with_output(struct output *output, + struct wlr_output_layout *output_layout, + struct wlr_box *surface_box) +{ + /* The resolution can change if outputs are rotated */ + struct wlr_box output_box = {0}; + wlr_output_effective_resolution(output->wlr_output, &output_box.width, + &output_box.height); + struct wlr_box intersection; + return wlr_box_intersection(&intersection, &output_box, surface_box); +} + static void -draw_rect(struct draw_data *d, struct wlr_box box) +output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy, + void *user_data) { - double ox = 0, oy = 0; - wlr_output_layout_output_coords(d->output_layout, d->output, &ox, &oy); - box.x += ox; - box.y += oy; - wlr_render_rect(d->renderer, &box, d->rgba, d->transform_matrix); + struct surface_iterator_data *data = user_data; + struct output *output = data->output; + if (!surface || !wlr_surface_has_buffer(surface)) { + return; + } + struct wlr_box surface_box = { + .x = data->ox + sx + surface->sx, + .y = data->oy + sy + surface->sy, + .width = surface->current.width, + .height = surface->current.height, + }; + + if (!intersects_with_output(output, output->server->output_layout, + &surface_box)) { + return; + } + data->user_iterator(data->output, surface, &surface_box, + data->user_data); +} + +void +output_surface_for_each_surface(struct output *output, + struct wlr_surface *surface, double ox, double oy, + surface_iterator_func_t iterator, void *user_data) +{ + struct surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .output = output, + .ox = ox, + .oy = oy, + }; + if (!surface) { + return; + } + wlr_surface_for_each_surface(surface, + output_for_each_surface_iterator, &data); +} + +struct render_data { + pixman_region32_t *damage; +}; + +int +scale_length(int length, int offset, float scale) +{ + return round((offset + length) * scale) - round(offset * scale); +} + +void +scale_box(struct wlr_box *box, float scale) +{ + box->width = scale_length(box->width, box->x, scale); + box->height = scale_length(box->height, box->y, scale); + box->x = round(box->x * scale); + box->y = round(box->y * scale); } static void -draw_line(struct draw_data *d, int x1, int y1, int x2, int y2) +scissor_output(struct wlr_output *output, pixman_box32_t *rect) { + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_box box = { - .x = x1, - .y = y1, - .width = abs(x2 - x1) + 1, - .height = abs(y2 - y1) + 1, + .x = rect->x1, + .y = rect->y1, + .width = rect->x2 - rect->x1, + .height = rect->y2 - rect->y1, }; - wlr_render_rect(d->renderer, &box, d->rgba, d->transform_matrix); + + int output_width, output_height; + wlr_output_transformed_resolution(output, &output_width, &output_height); + enum wl_output_transform transform = + wlr_output_transform_invert(output->transform); + wlr_box_transform(&box, &box, transform, output_width, output_height); + + wlr_renderer_scissor(renderer, &box); +} + +static void +render_texture(struct wlr_output *wlr_output, pixman_region32_t *output_damage, + struct wlr_texture *texture, const struct wlr_box *box, + const float matrix[static 9]) +{ + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + + 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); + if (!pixman_region32_not_empty(&damage)) { + goto damage_finish; + } + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; i++) { + scissor_output(wlr_output, &rects[i]); + wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f); + } + +damage_finish: + pixman_region32_fini(&damage); } -static void draw_rect_unfilled(struct draw_data *d, struct wlr_box box) +static void +render_surface_iterator(struct output *output, struct wlr_surface *surface, + struct wlr_box *box, void *user_data) { - draw_line(d, box.x, box.y, box.x + box.width - 1, box.y); - draw_line(d, box.x + box.width - 1, box.y, box.x + box.width - 1, - box.y + box.height - 1); - draw_line(d, box.x, box.y + box.height - 1, box.x + box.width - 1, - box.y + box.height - 1); - draw_line(d, box.x, box.y, box.x, box.y + box.height - 1); + struct render_data *data = user_data; + struct wlr_output *wlr_output = output->wlr_output; + pixman_region32_t *output_damage = data->damage; + + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (!texture) { + wlr_log(WLR_DEBUG, "Cannot obtain surface texture"); + return; + } + + scale_box(box, wlr_output->scale); + + float matrix[9]; + enum wl_output_transform transform = + wlr_output_transform_invert(surface->current.transform); + wlr_matrix_project_box(matrix, box, transform, 0.0f, + wlr_output->transform_matrix); + + render_texture(wlr_output, output_damage, texture, box, matrix); +} + +#if HAVE_XWAYLAND +void +output_unmanaged_for_each_surface(struct output *output, + struct wl_list *unmanaged, surface_iterator_func_t iterator, + void *user_data) +{ + struct xwayland_unmanaged *unmanaged_surface; + wl_list_for_each(unmanaged_surface, unmanaged, link) { + struct wlr_xwayland_surface *xsurface = + unmanaged_surface->xwayland_surface; + double ox = unmanaged_surface->lx, oy = unmanaged_surface->ly; + wlr_output_layout_output_coords( + output->server->output_layout, output->wlr_output, &ox, &oy); + output_surface_for_each_surface(output, xsurface->surface, ox, oy, + iterator, user_data); + } +} + +static void render_unmanaged(struct output *output, pixman_region32_t *damage, + struct wl_list *unmanaged) { + struct render_data data = { + .damage = damage, + }; + output_unmanaged_for_each_surface(output, unmanaged, + render_surface_iterator, &data); +} +#endif + +static void +output_view_for_each_surface(struct output *output, struct view *view, + surface_iterator_func_t iterator, void *user_data) +{ + struct surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .output = output, + .ox = view->x, + .oy = view->y, + }; + + wlr_output_layout_output_coords(output->server->output_layout, + output->wlr_output, &data.ox, &data.oy); + view_for_each_surface(view, output_for_each_surface_iterator, &data); +} + +void +output_view_for_each_popup(struct output *output, struct view *view, + surface_iterator_func_t iterator, void *user_data) +{ + struct surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .output = output, + .ox = view->x, + .oy = view->y, + }; + + wlr_output_layout_output_coords(output->server->output_layout, + output->wlr_output, &data.ox, &data.oy); + view_for_each_popup(view, output_for_each_surface_iterator, &data); +} + +/* for sending frame done */ +void output_layer_for_each_surface(struct output *output, + struct wl_list *layer_surfaces, surface_iterator_func_t iterator, + void *user_data) { + struct lab_layer_surface *layer_surface; + wl_list_for_each(layer_surface, layer_surfaces, link) { + struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = + layer_surface->layer_surface; + output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, + layer_surface->geo.x, layer_surface->geo.y, iterator, + user_data); + /* TODO: handle popups */ + } +} + +static void +output_for_each_surface(struct output *output, surface_iterator_func_t iterator, + void *user_data) +{ + output_layer_for_each_surface(output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], + iterator, user_data); + output_layer_for_each_surface(output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], + iterator, user_data); + + struct view *view; + wl_list_for_each_reverse(view, &output->server->views, link) { + if (!view->mapped) { + continue; + } + output_view_for_each_surface(output, view, iterator, user_data); + } + +#if HAVE_XWAYLAND + output_unmanaged_for_each_surface(output, &output->server->unmanaged_surfaces, + iterator, user_data); +#endif + + output_layer_for_each_surface(output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + iterator, user_data); + output_layer_for_each_surface(output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + iterator, user_data); +} + +struct send_frame_done_data { + struct timespec when; +}; + +static void +send_frame_done_iterator(struct output *output, struct wlr_surface *surface, + struct wlr_box *box, void *user_data) +{ + struct send_frame_done_data *data = user_data; + wlr_surface_send_frame_done(surface, &data->when); +} + +static void +send_frame_done(struct output *output, struct send_frame_done_data *data) +{ + output_for_each_surface(output, send_frame_done_iterator, data); +} + +void +render_rect(struct output *output, pixman_region32_t *output_damage, + const struct wlr_box *_box, float color[static 4]) +{ + struct wlr_output *wlr_output = output->wlr_output; + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + + struct wlr_box box; + memcpy(&box, _box, sizeof(struct wlr_box)); + + 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; + } + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_render_rect(renderer, &box, color, + wlr_output->transform_matrix); + } + +damage_finish: + pixman_region32_fini(&damage); +} + +void +render_rect_unfilled(struct output *output, pixman_region32_t *output_damage, + const struct wlr_box *_box, float color[static 4]) +{ + struct wlr_box box; + memcpy(&box, _box, sizeof(struct wlr_box)); + box.height = 1; + render_rect(output, output_damage, &box, color); + box.y += _box->height - 1; + render_rect(output, output_damage, &box, color); + memcpy(&box, _box, sizeof(struct wlr_box)); + box.width = 1; + render_rect(output, output_damage, &box, color); + box.x += _box->width - 1; + render_rect(output, output_damage, &box, color); } static void @@ -56,105 +364,61 @@ shrink(struct wlr_box *box, int size) } static void -render_cycle_box(struct output *output) +render_cycle_box(struct output *output, pixman_region32_t *output_damage, + struct view *view) { struct wlr_output_layout *layout = output->server->output_layout; double ox = 0, oy = 0; struct wlr_box box; - if (!output->server->cycle_view) - return; - struct view *view; - wl_list_for_each_reverse (view, &output->server->views, link) { - if (view == output->server->cycle_view) - goto render_it; - } - return; -render_it: wlr_output_layout_output_coords(layout, output->wlr_output, &ox, &oy); box.x = view->x - view->margin.left + ox; box.y = view->y - view->margin.top + oy; box.width = view->w + view->margin.left + view->margin.right; box.height = view->h + view->margin.top + view->margin.bottom; - struct draw_data dd = { - .renderer = view->server->renderer, - .transform_matrix = output->wlr_output->transform_matrix, - }; - dd.rgba = (float[4]){ 1.0, 1.0, 1.0, 1.0 }; - draw_rect_unfilled(&dd, box); - dd.rgba = (float[4]){ 0.0, 0.0, 0.0, 1.0 }; + + float white[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + render_rect_unfilled(output, output_damage, &box, white); + for (int i = 0; i < 4; i++) { shrink(&box, 1); - draw_rect_unfilled(&dd, box); + render_rect_unfilled(output, output_damage, &box, black); } - dd.rgba = (float[4]){ 1.0, 1.0, 1.0, 1.0 }; shrink(&box, 1); - draw_rect_unfilled(&dd, box); + render_rect_unfilled(output, output_damage, &box, white); } static void -render_rootmenu(struct output *output) +render_icon(struct output *output, pixman_region32_t *output_damage, + struct wlr_box *box, struct wlr_texture *texture) { - struct server *server = output->server; - struct draw_data ddata = { - .renderer = server->renderer, - .transform_matrix = output->wlr_output->transform_matrix, - }; - float matrix[9]; - - struct wlr_output_layout *output_layout = server->output_layout; - double ox = 0, oy = 0; - wlr_output_layout_output_coords(output_layout, output->wlr_output, &ox, &oy); - ddata.rgba = (float[4]){ 0.9, 0.3, 0.3, 0.5 }; - struct menuitem *menuitem; - wl_list_for_each (menuitem, &server->rootmenu->menuitems, link) { - struct wlr_texture *t; - t = menuitem->selected ? menuitem->active_texture : - menuitem->inactive_texture; - struct wlr_box box = { - .x = menuitem->geo_box.x + ox, - .y = menuitem->geo_box.y + oy, - .width = menuitem->geo_box.width, - .height = menuitem->geo_box.height, - }; - wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, - 0, ddata.transform_matrix); - wlr_render_texture_with_matrix(ddata.renderer, t, matrix, 1); - } - -} - -static void -render_icon(struct draw_data *d, struct wlr_box box, - struct wlr_texture *texture) -{ - if (!texture) - return; - float matrix[9]; - /* centre-align icon if smaller than designated box */ struct wlr_box button; wlr_texture_get_size(texture, &button.width, &button.height); - if (box.width > button.width) { - button.x = box.x + (box.width - button.width) / 2; + if (box->width > button.width) { + button.x = box->x + (box->width - button.width) / 2; } else { - button.x = box.x; - button.width = box.width; + button.x = box->x; + button.width = box->width; } - if (box.height > button.height) { - button.y = box.y + (box.height - button.height) / 2; + if (box->height > button.height) { + button.y = box->y + (box->height - button.height) / 2; } else { - button.y = box.y; - button.height = box.height; + button.y = box->y; + button.height = box->height; } double ox = 0, oy = 0; - wlr_output_layout_output_coords(d->output_layout, d->output, &ox, &oy); + wlr_output_layout_output_coords(output->server->output_layout, + output->wlr_output, &ox, &oy); button.x += ox; button.y += oy; + float matrix[9]; wlr_matrix_project_box(matrix, &button, WL_OUTPUT_TRANSFORM_NORMAL, 0, - d->transform_matrix); - wlr_render_texture_with_matrix(d->renderer, texture, matrix, 1); + output->wlr_output->transform_matrix); + render_texture(output->wlr_output, output_damage, texture, &button, + matrix); } static bool @@ -166,251 +430,359 @@ isbutton(enum deco_part deco_part) } static void -render_decorations(struct wlr_output *output, struct view *view) +render_deco(struct view *view, struct output *output, + pixman_region32_t *output_damage) { - if (!view->server_side_deco) + if (!view->server_side_deco) { return; - struct draw_data ddata = { - .output = output, - .output_layout = view->server->output_layout, - .renderer = view->server->renderer, - .transform_matrix = output->transform_matrix, - }; + } - /* border */ - ddata.rgba = theme.window_active_handle_bg_color; - draw_rect(&ddata, deco_box(view, LAB_DECO_PART_TOP)); - draw_rect(&ddata, deco_box(view, LAB_DECO_PART_RIGHT)); - draw_rect(&ddata, deco_box(view, LAB_DECO_PART_BOTTOM)); - draw_rect(&ddata, deco_box(view, LAB_DECO_PART_LEFT)); + /* render border */ + float *color = theme.window_active_handle_bg_color; + enum deco_part border[4] = { + LAB_DECO_PART_TOP, + LAB_DECO_PART_RIGHT, + LAB_DECO_PART_BOTTOM, + LAB_DECO_PART_LEFT, + }; + for (int i = 0; i < 4; i++) { + struct wlr_box box = deco_box(view, border[i]); + render_rect(output, output_damage, &box, color); + } - /* title */ + /* render title */ struct wlr_seat *seat = view->server->seat.seat; - if (view->surface == seat->keyboard_state.focused_surface) - ddata.rgba = theme.window_active_title_bg_color; - else - ddata.rgba = theme.window_inactive_title_bg_color; - draw_rect(&ddata, deco_box(view, LAB_DECO_PART_TITLE)); + if (view->surface == seat->keyboard_state.focused_surface) { + color = theme.window_active_title_bg_color; + } else { + color = theme.window_inactive_title_bg_color; + } + struct wlr_box box = deco_box(view, LAB_DECO_PART_TITLE); + render_rect(output, output_damage, &box, color); /* button background */ struct wlr_cursor *cur = view->server->seat.cursor; enum deco_part deco_part = deco_at(view, cur->x, cur->y); - - struct wlr_box box = deco_box(view, deco_part); + box = deco_box(view, deco_part); if (isbutton(deco_part) && wlr_box_contains_point(&box, cur->x, cur->y)) { - ddata.rgba = (float[4]){ 0.5, 0.5, 0.5, 0.5 }; - draw_rect(&ddata, deco_box(view, deco_part)); + color = (float[4]){ 0.5, 0.5, 0.5, 0.5 }; + render_rect(output, output_damage, &box, color); } /* buttons */ if (view->surface == seat->keyboard_state.focused_surface) { - render_icon(&ddata, deco_box(view, LAB_DECO_BUTTON_CLOSE), - theme.xbm_close_active_unpressed); - render_icon(&ddata, deco_box(view, LAB_DECO_BUTTON_MAXIMIZE), - theme.xbm_maximize_active_unpressed); - render_icon(&ddata, deco_box(view, LAB_DECO_BUTTON_ICONIFY), - theme.xbm_iconify_active_unpressed); + box = deco_box(view, LAB_DECO_BUTTON_CLOSE); + render_icon(output, output_damage, &box, + theme.xbm_close_active_unpressed); + box = deco_box(view, LAB_DECO_BUTTON_MAXIMIZE); + render_icon(output, output_damage, &box, + theme.xbm_maximize_active_unpressed); + box = deco_box(view, LAB_DECO_BUTTON_ICONIFY); + render_icon(output, output_damage, &box, + theme.xbm_iconify_active_unpressed); } else { - render_icon(&ddata, deco_box(view, LAB_DECO_BUTTON_CLOSE), - theme.xbm_close_inactive_unpressed); - render_icon(&ddata, deco_box(view, LAB_DECO_BUTTON_MAXIMIZE), - theme.xbm_maximize_inactive_unpressed); - render_icon(&ddata, deco_box(view, LAB_DECO_BUTTON_ICONIFY), - theme.xbm_iconify_inactive_unpressed); + box = deco_box(view, LAB_DECO_BUTTON_CLOSE); + render_icon(output, output_damage, &box, + theme.xbm_close_inactive_unpressed); + box = deco_box(view, LAB_DECO_BUTTON_MAXIMIZE); + render_icon(output, output_damage, &box, + theme.xbm_maximize_inactive_unpressed); + box = deco_box(view, LAB_DECO_BUTTON_ICONIFY); + render_icon(output, output_damage, &box, + theme.xbm_iconify_inactive_unpressed); } } -struct render_data_layer { - struct lab_layer_surface *layer_surface; - struct timespec *now; -}; - static void -render_layer_surface(struct wlr_surface *surface, int sx, int sy, void *data) +render_rootmenu(struct output *output, pixman_region32_t *output_damage) { - struct render_data_layer *context = data; - struct lab_layer_surface *layer_surface = context->layer_surface; - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (texture == NULL) { - return; - } - struct wlr_output *output = layer_surface->layer_surface->output; - double ox = 0, oy = 0; - wlr_output_layout_output_coords( - layer_surface->server->output_layout, output, &ox, &oy); - ox += layer_surface->geo.x + sx, oy += layer_surface->geo.y + sy; + struct server *server = output->server; float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - struct wlr_box box; - memcpy(&box, &layer_surface->geo, sizeof(struct wlr_box)); - wlr_matrix_project_box(matrix, &box, transform, 0, - output->transform_matrix); - wlr_render_texture_with_matrix(layer_surface->server->renderer, - texture, matrix, 1); - wlr_surface_send_frame_done(surface, context->now); + + struct wlr_output_layout *output_layout = server->output_layout; + double ox = 0, oy = 0; + wlr_output_layout_output_coords(output_layout, output->wlr_output, + &ox, &oy); + struct menuitem *menuitem; + wl_list_for_each (menuitem, &server->rootmenu->menuitems, link) { + struct wlr_texture *t; + t = menuitem->selected ? menuitem->active_texture : + menuitem->inactive_texture; + struct wlr_box box = { + .x = menuitem->geo_box.x + ox, + .y = menuitem->geo_box.y + oy, + .width = menuitem->geo_box.width, + .height = menuitem->geo_box.height, + }; + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, + 0, output->wlr_output->transform_matrix); + render_texture(output->wlr_output, output_damage, t, + &box, matrix); + } } -static void -render_layer(struct timespec *now, struct wl_list *layer_surfaces) +void output_layer_for_each_surface_toplevel(struct output *output, + struct wl_list *layer_surfaces, surface_iterator_func_t iterator, + void *user_data) { - struct render_data_layer context = { - .now = now, - }; struct lab_layer_surface *layer_surface; wl_list_for_each(layer_surface, layer_surfaces, link) { struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = layer_surface->layer_surface; - context.layer_surface = layer_surface; - wlr_surface_for_each_surface(wlr_layer_surface_v1->surface, - render_layer_surface, &context); + output_surface_for_each_surface(output, + wlr_layer_surface_v1->surface, layer_surface->geo.x, + layer_surface->geo.y, iterator, user_data); } } -struct render_data { - struct wlr_output *output; - struct wlr_output_layout *output_layout; - struct wlr_renderer *renderer; - int lx, ly; - struct timespec *when; -}; +static void render_layer_toplevel(struct output *output, + pixman_region32_t *damage, struct wl_list *layer_surfaces) { + struct render_data data = { + .damage = damage, + }; + output_layer_for_each_surface_toplevel(output, layer_surfaces, + render_surface_iterator, &data); +} static void -render_surface(struct wlr_surface *surface, int sx, int sy, void *data) +render_view_toplevels(struct view *view, struct output *output, + pixman_region32_t *damage) { - struct render_data *rdata = data; - - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (!texture) { - return; - } - - /* - * The view has a position in layout coordinates. If you have two - * displays, one next to the other, both 1080p, a view on the rightmost - * display might have layout coordinates of 2000,100. We need to - * translate that to output-local coordinates, or (2000 - 1920). - */ - double ox = 0, oy = 0; - wlr_output_layout_output_coords( - rdata->output_layout, rdata->output, &ox, &oy); - ox += rdata->lx + sx; - oy += rdata->ly + sy; - - struct wlr_box box = { - .x = ox * rdata->output->scale, - .y = oy * rdata->output->scale, - .width = surface->current.width * rdata->output->scale, - .height = surface->current.height * rdata->output->scale, + struct render_data data = { + .damage = damage, }; + double ox = view->x; + double oy = view->y; + wlr_output_layout_output_coords(output->server->output_layout, + output->wlr_output, &ox, &oy); + output_surface_for_each_surface(output, view->surface, ox, oy, + render_surface_iterator, &data); +} - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &box, transform, 0, - rdata->output->transform_matrix); +static void +render_popup_iterator(struct output *output, struct wlr_surface *surface, + struct wlr_box *box, void *data) +{ + /* Render this popup's surface */ + render_surface_iterator(output, surface, box, data); - wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1); - wlr_surface_send_frame_done(surface, rdata->when); + /* Render this popup's child toplevels */ + output_surface_for_each_surface(output, surface, box->x, box->y, + render_surface_iterator, data); } static void -output_frame_notify(struct wl_listener *listener, void *data) +render_view_popups(struct view *view, struct output *output, + pixman_region32_t *damage) { - /* - * This function is called every time an output is ready to display a - * frame, generally at the output's refresh rate (e.g. 60Hz). - */ - struct output *output = wl_container_of(listener, output, frame); - struct wlr_renderer *renderer = output->server->renderer; + struct render_data data = { + .damage = damage, + }; + output_view_for_each_popup(output, view, render_popup_iterator, &data); +} - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); +void +output_render(struct output *output, pixman_region32_t *damage) +{ + struct server *server = output->server; + struct wlr_output *wlr_output = output->wlr_output; - /* wlr_output_attach_render makes the OpenGL context current. */ - if (!wlr_output_attach_render(output->wlr_output, NULL)) { + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + if (!renderer) { + wlr_log(WLR_DEBUG, "no renderer"); return; } - /* The "effective" resolution can change if you rotate your outputs. */ - int width, height; - wlr_output_effective_resolution(output->wlr_output, &width, &height); - /* Calls glViewport and some other GL sanity checks */ - wlr_renderer_begin(renderer, width, height); + wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); - float color[4] = { 0.3, 0.3, 0.3, 1.0 }; - wlr_renderer_clear(renderer, color); + if (!pixman_region32_not_empty(damage)) { + goto renderer_end; + } - render_layer(&now, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer(&now, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); +#ifdef DEBUG + wlr_renderer_clear(renderer, (float[]){0.2f, 0.0f, 0.0f, 1.0f}); +#endif + + float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); + for (int i = 0; i < nrects; i++) { + scissor_output(wlr_output, &rects[i]); + wlr_renderer_clear(renderer, color); + } + + render_layer_toplevel(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + render_layer_toplevel(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); struct view *view; - wl_list_for_each_reverse (view, &output->server->views, link) { - if (!view->mapped) + wl_list_for_each_reverse (view, &server->views, link) { + if (!view->mapped) { continue; + } + render_deco(view, output, damage); + render_view_toplevels(view, output, damage); + render_view_popups(view, output, damage); + } - render_decorations(output->wlr_output, view); +#if HAVE_XWAYLAND + render_unmanaged(output, damage, &output->server->unmanaged_surfaces); +#endif - struct render_data rdata = { - .output = output->wlr_output, - .output_layout = output->server->output_layout, - .lx = view->x, - .ly = view->y, - .renderer = renderer, - .when = &now, - }; + /* 'alt-tab' border */ + if (output->server->cycle_view) { + render_cycle_box(output, damage, output->server->cycle_view); + } + + render_layer_toplevel(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + render_layer_toplevel(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - view_for_each_surface(view, render_surface, &rdata); + if (output->server->input_mode == LAB_INPUT_STATE_MENU) { + render_rootmenu(output, damage); } - /* If in cycle (alt-tab) mode, highlight selected view */ - render_cycle_box(output); +renderer_end: + /* Just in case hardware cursors not supported by GPU */ + wlr_output_render_software_cursors(wlr_output, damage); + wlr_renderer_scissor(renderer, NULL); + wlr_renderer_end(renderer); -#if HAVE_XWAYLAND - /* Render xwayland override_redirect surfaces */ - struct xwayland_unmanaged *unmanaged; - wl_list_for_each_reverse (unmanaged, - &output->server->unmanaged_surfaces, link) { - struct render_data rdata = { - .output = output->wlr_output, - .output_layout = output->server->output_layout, - .lx = unmanaged->lx, - .ly = unmanaged->ly, - .renderer = renderer, - .when = &now, - }; + int output_width, output_height; + wlr_output_transformed_resolution(wlr_output, &output_width, + &output_height); - struct wlr_surface *s = unmanaged->xwayland_surface->surface; - render_surface(s, 0, 0, &rdata); - } + pixman_region32_t frame_damage; + pixman_region32_init(&frame_damage); + + enum wl_output_transform transform = + wlr_output_transform_invert(wlr_output->transform); + wlr_region_transform(&frame_damage, &output->damage->current, + transform, output_width, output_height); + +#ifdef DEBUG + pixman_region32_union_rect(&frame_damage, &frame_damage, 0, 0, + output_width, output_height); #endif - render_layer(&now, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - render_layer(&now, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + wlr_output_set_damage(wlr_output, &frame_damage); + pixman_region32_fini(&frame_damage); - if (output->server->input_mode == LAB_INPUT_STATE_MENU) { - render_rootmenu(output); + if (!wlr_output_commit(wlr_output)) { + wlr_log(WLR_ERROR, "could not commit output"); } +} - /* Just in case hardware cursors not supported by GPU */ - wlr_output_render_software_cursors(output->wlr_output, NULL); +static void +damage_surface_iterator(struct output *output, struct wlr_surface *surface, + struct wlr_box *box, void *user_data) +{ + struct wlr_output *wlr_output = output->wlr_output; + bool whole = *(bool *) user_data; + + scale_box(box, output->wlr_output->scale); + + if (whole) { + wlr_output_damage_add_box(output->damage, box); + } else if (pixman_region32_not_empty(&surface->buffer_damage)) { + pixman_region32_t damage; + pixman_region32_init(&damage); + wlr_surface_get_effective_damage(surface, &damage); + + wlr_region_scale(&damage, &damage, wlr_output->scale); + if (ceil(wlr_output->scale) > surface->current.scale) { + wlr_region_expand(&damage, &damage, + ceil(wlr_output->scale) - surface->current.scale); + } + pixman_region32_translate(&damage, box->x, box->y); + wlr_output_damage_add(output->damage, &damage); + pixman_region32_fini(&damage); + } +} - wlr_renderer_end(renderer); - wlr_output_commit(output->wlr_output); +void +output_damage_surface(struct output *output, struct wlr_surface *surface, + double lx, double ly, bool whole) +{ + if (!output->wlr_output->enabled) { + return; + } + + double ox = lx, oy = ly; + wlr_output_layout_output_coords(output->server->output_layout, + output->wlr_output, &ox, &oy); + output_surface_for_each_surface(output, surface, ox, oy, + damage_surface_iterator, &whole); } static void -output_destroy_notify(struct wl_listener *listener, void *data) +output_damage_frame_notify(struct wl_listener *listener, void *data) { - struct output *output = wl_container_of(listener, output, destroy); + struct output *output = wl_container_of(listener, output, damage_frame); + + if (!output->wlr_output->enabled) { + return; + } + + bool needs_frame; + pixman_region32_t damage; + pixman_region32_init(&damage); + if (!wlr_output_damage_attach_render(output->damage, + &needs_frame, &damage)) { + return; + } + + if (needs_frame) { + output_render(output, &damage); + } else { + wlr_output_rollback(output->wlr_output); + } + pixman_region32_fini(&damage); + + struct send_frame_done_data frame_data = {0}; + clock_gettime(CLOCK_MONOTONIC, &frame_data.when); + send_frame_done(output, &frame_data); +} + +static void +output_destroy(struct output *output) +{ + if (!output || output->server->output_layout || !output->wlr_output) { + return; + } wl_list_remove(&output->link); - wl_list_remove(&output->frame.link); wl_list_remove(&output->destroy.link); + wl_list_remove(&output->damage_frame.link); + wl_list_remove(&output->damage_destroy.link); + + struct server *server = output->server; + wlr_output_layout_remove(server->output_layout, output->wlr_output); free(output); } +static void +output_damage_destroy_notify(struct wl_listener *listener, void *data) +{ + struct output *output = wl_container_of(listener, output, damage_destroy); + output_destroy(output); +} + +static void +output_destroy_notify(struct wl_listener *listener, void *data) +{ + struct output *output = wl_container_of(listener, output, destroy); + if (!output || !output->wlr_output || !output->damage) { + return; + } + wlr_output_damage_destroy(output->damage); + output_destroy(output); +} + static void new_output_notify(struct wl_listener *listener, void *data) { @@ -432,12 +804,17 @@ new_output_notify(struct wl_listener *listener, void *data) struct output *output = calloc(1, sizeof(struct output)); output->wlr_output = wlr_output; output->server = server; - output->frame.notify = output_frame_notify; - wl_signal_add(&wlr_output->events.frame, &output->frame); + output->damage = wlr_output_damage_create(wlr_output); wl_list_insert(&server->outputs, &output->link); + output->destroy.notify = output_destroy_notify; wl_signal_add(&wlr_output->events.destroy, &output->destroy); + output->damage_frame.notify = output_damage_frame_notify; + wl_signal_add(&output->damage->events.frame, &output->damage_frame); + output->damage_destroy.notify = output_damage_destroy_notify; + wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); + wl_list_init(&output->layers[0]); wl_list_init(&output->layers[1]); wl_list_init(&output->layers[2]); diff --git a/src/view.c b/src/view.c index a6ab8971..c1e456bf 100644 --- a/src/view.c +++ b/src/view.c @@ -39,3 +39,13 @@ view_for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, view->impl->for_each_surface(view, iterator, user_data); } +void +view_for_each_popup(struct view *view, wlr_surface_iterator_func_t iterator, + void *data) +{ + if (!view->impl->for_each_popup) { + return; + } + view->impl->for_each_popup(view, iterator, data); +} + diff --git a/src/xdg.c b/src/xdg.c index 180228ac..ee4d478b 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -52,6 +52,86 @@ xdg_toplevel_decoration(struct wl_listener *listener, void *data) xdg_deco_request_mode(&xdg_deco->request_mode, wlr_decoration); } +static void +handle_xdg_popup_commit(struct wl_listener *listener, void *data) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, map); + /* TODO */ +} + +static void +handle_xdg_popup_map(struct wl_listener *listener, void *data) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, map); + damage_view_whole(popup->view); +} + +static void +handle_xdg_popup_unmap(struct wl_listener *listener, void *data) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, unmap); + damage_view_whole(popup->view); +} + +static void +handle_xdg_popup_destroy(struct wl_listener *listener, void *data) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, destroy); + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->commit.link); + wl_list_remove(&popup->map.link); + wl_list_remove(&popup->unmap.link); + wl_list_remove(&popup->new_popup.link); + free(popup); +} + +static void xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup); + +static void +popup_handle_new_xdg_popup(struct wl_listener *listener, void *data) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + xdg_popup_create(popup->view, wlr_popup); +} + +/* + * We need to pass view to this function for damage tracking. + * TODO: Could we just damage surface or whole output? + * That would allow us to only have one 'handle_new_*' + */ +static void +xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup) +{ + struct xdg_popup *popup = calloc(1, sizeof(struct xdg_popup)); + if (!popup) { + return; + } + + popup->wlr_popup = wlr_popup; + popup->view = view; + + popup->destroy.notify = handle_xdg_popup_destroy; + wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); + popup->commit.notify = handle_xdg_popup_commit; + wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); + popup->map.notify = handle_xdg_popup_map; + wl_signal_add(&wlr_popup->base->events.map, &popup->map); + popup->unmap.notify = handle_xdg_popup_unmap; + wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap); + popup->new_popup.notify = popup_handle_new_xdg_popup; + wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); +} + +/* This is merely needed to track damage */ +static void +handle_new_xdg_popup(struct wl_listener *listener, void *data) +{ + struct view *view = wl_container_of(listener, view, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + xdg_popup_create(view, wlr_popup); +} + static bool has_ssd(struct view *view) { @@ -95,6 +175,7 @@ handle_commit(struct wl_listener *listener, void *data) view->pending_move_resize.configure_serial = 0; } } + damage_view_part(view); } static void @@ -165,6 +246,7 @@ xdg_toplevel_view_configure(struct view *view, struct wlr_box geo) } else if (view->pending_move_resize.configure_serial == 0) { view->x = geo.x; view->y = geo.y; + damage_all_outputs(view->server); } } @@ -173,6 +255,7 @@ xdg_toplevel_view_move(struct view *view, double x, double y) { view->x = x; view->y = y; + damage_all_outputs(view->server); } static void @@ -181,6 +264,13 @@ xdg_toplevel_view_close(struct view *view) wlr_xdg_toplevel_send_close(view->xdg_surface); } +static void +xdg_toplevel_view_for_each_popup(struct view *view, + wlr_surface_iterator_func_t iterator, void *data) +{ + wlr_xdg_surface_for_each_popup(view->xdg_surface, iterator, data); +} + static void xdg_toplevel_view_for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, void *data) @@ -234,12 +324,14 @@ xdg_toplevel_view_map(struct view *view) view->commit.notify = handle_commit; desktop_focus_view(&view->server->seat, view); + damage_all_outputs(view->server); } static void xdg_toplevel_view_unmap(struct view *view) { view->mapped = false; + damage_all_outputs(view->server); wl_list_remove(&view->commit.link); desktop_focus_topmost_mapped_view(view->server); } @@ -247,6 +339,7 @@ xdg_toplevel_view_unmap(struct view *view) static const struct view_impl xdg_toplevel_view_impl = { .configure = xdg_toplevel_view_configure, .close = xdg_toplevel_view_close, + .for_each_popup = xdg_toplevel_view_for_each_popup, .for_each_surface = xdg_toplevel_view_for_each_surface, .map = xdg_toplevel_view_map, .move = xdg_toplevel_view_move, @@ -277,6 +370,9 @@ xdg_surface_new(struct wl_listener *listener, void *data) view->destroy.notify = handle_destroy; wl_signal_add(&xdg_surface->events.destroy, &view->destroy); + view->new_popup.notify = handle_new_xdg_popup; + wl_signal_add(&xdg_surface->events.new_popup, &view->new_popup); + struct wlr_xdg_toplevel *toplevel = xdg_surface->toplevel; view->request_move.notify = handle_request_move; wl_signal_add(&toplevel->events.request_move, &view->request_move); diff --git a/src/xwayland-unmanaged.c b/src/xwayland-unmanaged.c index a9855d35..67c5acfc 100644 --- a/src/xwayland-unmanaged.c +++ b/src/xwayland-unmanaged.c @@ -19,6 +19,7 @@ unmanaged_handle_commit(struct wl_listener *listener, void *data) struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; unmanaged->lx = xsurface->x; unmanaged->ly = xsurface->y; + damage_all_outputs(unmanaged->server); } static void @@ -36,7 +37,7 @@ unmanaged_handle_map(struct wl_listener *listener, void *data) unmanaged->lx = xsurface->x; unmanaged->ly = xsurface->y; - + damage_all_outputs(unmanaged->server); if (wlr_xwayland_or_surface_wants_focus(xsurface)) { seat_focus_surface(&unmanaged->server->seat, xsurface->surface); } @@ -48,6 +49,7 @@ unmanaged_handle_unmap(struct wl_listener *listener, void *data) struct xwayland_unmanaged *unmanaged = wl_container_of(listener, unmanaged, unmap); struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; + damage_all_outputs(unmanaged->server); wl_list_remove(&unmanaged->link); wl_list_remove(&unmanaged->commit.link); diff --git a/src/xwayland.c b/src/xwayland.c index 9b2b2d49..6697580d 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -21,6 +21,7 @@ handle_commit(struct wl_listener *listener, void *data) view->pending_move_resize.height - view->h; view->pending_move_resize.update_y = false; } + damage_view_whole(view); } static void @@ -56,6 +57,7 @@ handle_request_configure(struct wl_listener *listener, void *data) struct wlr_xwayland_surface_configure_event *event = data; wlr_xwayland_surface_configure(view->xwayland_surface, event->x, event->y, event->width, event->height); + damage_all_outputs(view->server); } static void @@ -70,6 +72,7 @@ configure(struct view *view, struct wlr_box geo) wlr_xwayland_surface_configure(view->xwayland_surface, (int16_t)geo.x, (int16_t)geo.y, (uint16_t)geo.width, (uint16_t)geo.height); + damage_all_outputs(view->server); } static void @@ -80,18 +83,23 @@ move(struct view *view, double x, double y) struct wlr_xwayland_surface *s = view->xwayland_surface; wlr_xwayland_surface_configure(s, (int16_t)x, (int16_t)y, (uint16_t)s->width, (uint16_t)s->height); + damage_all_outputs(view->server); } static void _close(struct view *view) { wlr_xwayland_surface_close(view->xwayland_surface); + damage_all_outputs(view->server); } static void for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, void *data) { + if (!view->surface) { + return; + } wlr_surface_for_each_surface(view->surface, iterator, data); } @@ -139,12 +147,14 @@ map(struct view *view) view->commit.notify = handle_commit; desktop_focus_view(&view->server->seat, view); + damage_all_outputs(view->server); } static void unmap(struct view *view) { view->mapped = false; + damage_all_outputs(view->server); wl_list_remove(&view->commit.link); desktop_focus_topmost_mapped_view(view->server); } -- 2.52.0