Implement damage tracking

This commit is contained in:
Johan Malm 2021-01-09 22:51:20 +00:00
parent 695ce28b55
commit 54804fd3df
15 changed files with 881 additions and 321 deletions

View file

@ -35,7 +35,7 @@ The following were considered before choosing wlroots: [qtwayland](https://githu
Dependencies include: Dependencies include:
- meson, ninja - meson, ninja
- wlroots (>=0.11.0) - wlroots (0.11.0 - 0.12.0)
- wayland (>=1.16) - wayland (>=1.16)
- wayland-protocols - wayland-protocols
- xwayland, xcb (optional) - 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] Show maximize, iconify, close buttons
- [x] Catch SIGHUP to re-load config file and theme - [x] Catch SIGHUP to re-load config file and theme
- [x] Support layer-shell protocol ('exclusive' not yet implemented) - [x] Support layer-shell protocol ('exclusive' not yet implemented)
- [ ] Support root-menu and parse menu.xml (very simple implementation, not submenus yet) - [x] Support damage tracking to reduce CPU usage
- [ ] Support damage tracking to reduce CPU usage - [ ] Support root-menu and parse menu.xml (very simple implementation, no submenus yet)
- [ ] Support 'maximize' - [ ] Support 'maximize'
- [ ] Support wlr-output-management protocol and [kanshi](https://github.com/emersion/kanshi.git) - [ ] 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) - [ ] Support foreign-toplevel protocol (e.g. to integrate with wlroots panels/bars)

View file

@ -19,6 +19,7 @@
#include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_pointer.h> #include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_seat.h> #include <wlr/types/wlr_seat.h>
@ -123,9 +124,11 @@ struct output {
struct wl_list link; struct wl_list link;
struct server *server; struct server *server;
struct wlr_output *wlr_output; struct wlr_output *wlr_output;
struct wlr_output_damage *damage;
struct wl_list layers[4]; struct wl_list layers[4];
struct wl_listener frame;
struct wl_listener destroy; struct wl_listener destroy;
struct wl_listener damage_frame;
struct wl_listener damage_destroy;
}; };
enum view_type { enum view_type {
@ -151,6 +154,8 @@ enum deco_part {
struct view_impl { struct view_impl {
void (*configure)(struct view *view, struct wlr_box geo); void (*configure)(struct view *view, struct wlr_box geo);
void (*close)(struct view *view); 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, void (*for_each_surface)(struct view *view,
wlr_surface_iterator_func_t iterator, void *data); wlr_surface_iterator_func_t iterator, void *data);
void (*map)(struct view *view); void (*map)(struct view *view);
@ -211,6 +216,7 @@ struct view {
struct wl_listener request_move; struct wl_listener request_move;
struct wl_listener request_resize; struct wl_listener request_resize;
struct wl_listener request_configure; struct wl_listener request_configure;
struct wl_listener new_popup; /* xdg-shell only */
}; };
#if HAVE_XWAYLAND #if HAVE_XWAYLAND
@ -228,6 +234,17 @@ struct xwayland_unmanaged {
}; };
#endif #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_toplevel_decoration(struct wl_listener *listener, void *data);
void xdg_surface_new(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_unminimize(struct view *view);
void view_for_each_surface(struct view *view, void view_for_each_surface(struct view *view,
wlr_surface_iterator_func_t iterator, void *user_data); 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); 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); uint32_t edges);
void output_init(struct server *server); 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_init(struct server *server);
void server_start(struct server *server); void server_start(struct server *server);

View file

@ -49,6 +49,7 @@ glib = dependency('glib-2.0')
cairo = dependency('cairo') cairo = dependency('cairo')
pangocairo = dependency('pangocairo') pangocairo = dependency('pangocairo')
input = dependency('libinput', version: '>=1.14') input = dependency('libinput', version: '>=1.14')
pixman = dependency('pixman-1')
if get_option('xwayland').enabled() and not wlroots_has_xwayland if get_option('xwayland').enabled() and not wlroots_has_xwayland
error('no wlroots Xwayland support') error('no wlroots Xwayland support')
@ -63,7 +64,7 @@ subdir('protocols')
labwc_deps = [ labwc_deps = [
server_protos, wayland_server, wlroots, xkbcommon, xml2, glib, server_protos, wayland_server, wlroots, xkbcommon, xml2, glib,
cairo, pangocairo, input cairo, pangocairo, input, pixman
] ]
subdir('include') subdir('include')

View file

@ -15,6 +15,7 @@ show_menu(struct server *server, const char *menu)
menu_move(server->rootmenu, server->seat.cursor->x, menu_move(server->rootmenu, server->seat.cursor->x,
server->seat.cursor->y); server->seat.cursor->y);
} }
damage_all_outputs(server);
} }
void void
@ -29,6 +30,7 @@ action(struct server *server, const char *action, const char *command)
} else if (!strcasecmp(action, "Exit")) { } else if (!strcasecmp(action, "Exit")) {
wl_display_terminate(server->wl_display); wl_display_terminate(server->wl_display);
} else if (!strcasecmp(action, "NextWindow")) { } else if (!strcasecmp(action, "NextWindow")) {
dbg_show_views(server);
server->cycle_view = server->cycle_view =
desktop_cycle_view(server, server->cycle_view); desktop_cycle_view(server, server->cycle_view);
} else if (!strcasecmp(action, "Reconfigure")) { } else if (!strcasecmp(action, "Reconfigure")) {

View file

@ -66,6 +66,7 @@ request_set_selection_notify(struct wl_listener *listener, void *data)
static void static void
process_cursor_move(struct server *server, uint32_t time) process_cursor_move(struct server *server, uint32_t time)
{ {
damage_all_outputs(server);
/* Move the grabbed view to the new position. */ /* Move the grabbed view to the new position. */
double dx = server->seat.cursor->x - server->grab_x; double dx = server->seat.cursor->x - server->grab_x;
double dy = server->seat.cursor->y - server->grab_y; double dy = server->seat.cursor->y - server->grab_y;
@ -81,10 +82,7 @@ process_cursor_move(struct server *server, uint32_t time)
static void static void
process_cursor_resize(struct server *server, uint32_t time) process_cursor_resize(struct server *server, uint32_t time)
{ {
/* damage_all_outputs(server);
* TODO: Wait for the client to prepare a buffer at the new size, then
* commit any movement that was prepared.
*/
double dx = server->seat.cursor->x - server->grab_x; double dx = server->seat.cursor->x - server->grab_x;
double dy = server->seat.cursor->y - server->grab_y; 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) { } else if (server->input_mode == LAB_INPUT_STATE_MENU) {
menu_set_selected(server->rootmenu, menu_set_selected(server->rootmenu,
server->seat.cursor->x, server->seat.cursor->y); server->seat.cursor->x, server->seat.cursor->y);
damage_all_outputs(server);
return; return;
} }
@ -285,6 +284,7 @@ cursor_button(struct wl_listener *listener, void *data)
} }
/* Exit interactive move/resize/menu mode. */ /* Exit interactive move/resize/menu mode. */
server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; server->input_mode = LAB_INPUT_STATE_PASSTHROUGH;
damage_all_outputs(server);
return; return;
} }

32
src/damage.c Normal file
View file

@ -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);
}
}

View file

@ -148,6 +148,7 @@ desktop_cycle_view(struct server *server, struct view *current)
do { do {
view = wl_container_of(view->link.next, view, link); view = wl_container_of(view->link.next, view, link);
} while (&view->link == &server->views || !isfocusable(view)); } while (&view->link == &server->views || !isfocusable(view));
damage_all_outputs(server);
return view; return view;
} }

View file

@ -49,6 +49,7 @@ keyboard_key_notify(struct wl_listener *listener, void *data)
wlr_keyboard_get_modifiers(device->keyboard); wlr_keyboard_get_modifiers(device->keyboard);
if (server->cycle_view) { if (server->cycle_view) {
damage_all_outputs(server);
if ((syms[0] == XKB_KEY_Alt_L) && if ((syms[0] == XKB_KEY_Alt_L) &&
event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
/* end cycle */ /* end cycle */

View file

@ -258,6 +258,7 @@ surface_commit_notify(struct wl_listener *listener, void *data)
wl_container_of(listener, layer, surface_commit); wl_container_of(listener, layer, surface_commit);
struct wlr_output *wlr_output = layer->layer_surface->output; struct wlr_output *wlr_output = layer->layer_surface->output;
arrange_layers(output_from_wlr_output(layer->server, wlr_output)); arrange_layers(output_from_wlr_output(layer->server, wlr_output));
damage_all_outputs(layer->server);
} }
static void static void
@ -267,6 +268,7 @@ unmap(struct lab_layer_surface *layer)
if (seat->focused_layer == layer->layer_surface) { if (seat->focused_layer == layer->layer_surface) {
seat_set_focus_layer(seat, NULL); seat_set_focus_layer(seat, NULL);
} }
damage_all_outputs(layer->server);
} }
static void static void

View file

@ -1,6 +1,7 @@
labwc_sources = files( labwc_sources = files(
'action.c', 'action.c',
'cursor.c', 'cursor.c',
'damage.c',
'deco.c', 'deco.c',
'desktop.c', 'desktop.c',
'interactive.c', 'interactive.c',

File diff suppressed because it is too large Load diff

View file

@ -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); 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);
}

View file

@ -52,6 +52,86 @@ xdg_toplevel_decoration(struct wl_listener *listener, void *data)
xdg_deco_request_mode(&xdg_deco->request_mode, wlr_decoration); 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 static bool
has_ssd(struct view *view) has_ssd(struct view *view)
{ {
@ -95,6 +175,7 @@ handle_commit(struct wl_listener *listener, void *data)
view->pending_move_resize.configure_serial = 0; view->pending_move_resize.configure_serial = 0;
} }
} }
damage_view_part(view);
} }
static void 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) { } else if (view->pending_move_resize.configure_serial == 0) {
view->x = geo.x; view->x = geo.x;
view->y = geo.y; 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->x = x;
view->y = y; view->y = y;
damage_all_outputs(view->server);
} }
static void static void
@ -181,6 +264,13 @@ xdg_toplevel_view_close(struct view *view)
wlr_xdg_toplevel_send_close(view->xdg_surface); 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 static void
xdg_toplevel_view_for_each_surface(struct view *view, xdg_toplevel_view_for_each_surface(struct view *view,
wlr_surface_iterator_func_t iterator, void *data) wlr_surface_iterator_func_t iterator, void *data)
@ -234,12 +324,14 @@ xdg_toplevel_view_map(struct view *view)
view->commit.notify = handle_commit; view->commit.notify = handle_commit;
desktop_focus_view(&view->server->seat, view); desktop_focus_view(&view->server->seat, view);
damage_all_outputs(view->server);
} }
static void static void
xdg_toplevel_view_unmap(struct view *view) xdg_toplevel_view_unmap(struct view *view)
{ {
view->mapped = false; view->mapped = false;
damage_all_outputs(view->server);
wl_list_remove(&view->commit.link); wl_list_remove(&view->commit.link);
desktop_focus_topmost_mapped_view(view->server); 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 = { static const struct view_impl xdg_toplevel_view_impl = {
.configure = xdg_toplevel_view_configure, .configure = xdg_toplevel_view_configure,
.close = xdg_toplevel_view_close, .close = xdg_toplevel_view_close,
.for_each_popup = xdg_toplevel_view_for_each_popup,
.for_each_surface = xdg_toplevel_view_for_each_surface, .for_each_surface = xdg_toplevel_view_for_each_surface,
.map = xdg_toplevel_view_map, .map = xdg_toplevel_view_map,
.move = xdg_toplevel_view_move, .move = xdg_toplevel_view_move,
@ -277,6 +370,9 @@ xdg_surface_new(struct wl_listener *listener, void *data)
view->destroy.notify = handle_destroy; view->destroy.notify = handle_destroy;
wl_signal_add(&xdg_surface->events.destroy, &view->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; struct wlr_xdg_toplevel *toplevel = xdg_surface->toplevel;
view->request_move.notify = handle_request_move; view->request_move.notify = handle_request_move;
wl_signal_add(&toplevel->events.request_move, &view->request_move); wl_signal_add(&toplevel->events.request_move, &view->request_move);

View file

@ -19,6 +19,7 @@ unmanaged_handle_commit(struct wl_listener *listener, void *data)
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
unmanaged->lx = xsurface->x; unmanaged->lx = xsurface->x;
unmanaged->ly = xsurface->y; unmanaged->ly = xsurface->y;
damage_all_outputs(unmanaged->server);
} }
static void static void
@ -36,7 +37,7 @@ unmanaged_handle_map(struct wl_listener *listener, void *data)
unmanaged->lx = xsurface->x; unmanaged->lx = xsurface->x;
unmanaged->ly = xsurface->y; unmanaged->ly = xsurface->y;
damage_all_outputs(unmanaged->server);
if (wlr_xwayland_or_surface_wants_focus(xsurface)) { if (wlr_xwayland_or_surface_wants_focus(xsurface)) {
seat_focus_surface(&unmanaged->server->seat, xsurface->surface); 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 = struct xwayland_unmanaged *unmanaged =
wl_container_of(listener, unmanaged, unmap); wl_container_of(listener, unmanaged, unmap);
struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
damage_all_outputs(unmanaged->server);
wl_list_remove(&unmanaged->link); wl_list_remove(&unmanaged->link);
wl_list_remove(&unmanaged->commit.link); wl_list_remove(&unmanaged->commit.link);

View file

@ -21,6 +21,7 @@ handle_commit(struct wl_listener *listener, void *data)
view->pending_move_resize.height - view->h; view->pending_move_resize.height - view->h;
view->pending_move_resize.update_y = false; view->pending_move_resize.update_y = false;
} }
damage_view_whole(view);
} }
static void static void
@ -56,6 +57,7 @@ handle_request_configure(struct wl_listener *listener, void *data)
struct wlr_xwayland_surface_configure_event *event = data; struct wlr_xwayland_surface_configure_event *event = data;
wlr_xwayland_surface_configure(view->xwayland_surface, event->x, wlr_xwayland_surface_configure(view->xwayland_surface, event->x,
event->y, event->width, event->height); event->y, event->width, event->height);
damage_all_outputs(view->server);
} }
static void 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, wlr_xwayland_surface_configure(view->xwayland_surface, (int16_t)geo.x,
(int16_t)geo.y, (uint16_t)geo.width, (int16_t)geo.y, (uint16_t)geo.width,
(uint16_t)geo.height); (uint16_t)geo.height);
damage_all_outputs(view->server);
} }
static void static void
@ -80,18 +83,23 @@ move(struct view *view, double x, double y)
struct wlr_xwayland_surface *s = view->xwayland_surface; struct wlr_xwayland_surface *s = view->xwayland_surface;
wlr_xwayland_surface_configure(s, (int16_t)x, (int16_t)y, wlr_xwayland_surface_configure(s, (int16_t)x, (int16_t)y,
(uint16_t)s->width, (uint16_t)s->height); (uint16_t)s->width, (uint16_t)s->height);
damage_all_outputs(view->server);
} }
static void static void
_close(struct view *view) _close(struct view *view)
{ {
wlr_xwayland_surface_close(view->xwayland_surface); wlr_xwayland_surface_close(view->xwayland_surface);
damage_all_outputs(view->server);
} }
static void static void
for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator,
void *data) void *data)
{ {
if (!view->surface) {
return;
}
wlr_surface_for_each_surface(view->surface, iterator, data); wlr_surface_for_each_surface(view->surface, iterator, data);
} }
@ -139,12 +147,14 @@ map(struct view *view)
view->commit.notify = handle_commit; view->commit.notify = handle_commit;
desktop_focus_view(&view->server->seat, view); desktop_focus_view(&view->server->seat, view);
damage_all_outputs(view->server);
} }
static void static void
unmap(struct view *view) unmap(struct view *view)
{ {
view->mapped = false; view->mapped = false;
damage_all_outputs(view->server);
wl_list_remove(&view->commit.link); wl_list_remove(&view->commit.link);
desktop_focus_topmost_mapped_view(view->server); desktop_focus_topmost_mapped_view(view->server);
} }