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:
- 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)

View file

@ -19,6 +19,7 @@
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_matrix.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_pointer.h>
#include <wlr/types/wlr_seat.h>
@ -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);

View file

@ -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')

View file

@ -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")) {

View file

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

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 {
view = wl_container_of(view->link.next, view, link);
} while (&view->link == &server->views || !isfocusable(view));
damage_all_outputs(server);
return view;
}

View file

@ -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 */

View file

@ -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

View file

@ -1,6 +1,7 @@
labwc_sources = files(
'action.c',
'cursor.c',
'damage.c',
'deco.c',
'desktop.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);
}
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);
}
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);

View file

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

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