mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
Implement damage tracking
This commit is contained in:
parent
695ce28b55
commit
54804fd3df
15 changed files with 881 additions and 321 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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")) {
|
||||
|
|
|
|||
|
|
@ -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
32
src/damage.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
labwc_sources = files(
|
||||
'action.c',
|
||||
'cursor.c',
|
||||
'damage.c',
|
||||
'deco.c',
|
||||
'desktop.c',
|
||||
'interactive.c',
|
||||
|
|
|
|||
999
src/output.c
999
src/output.c
File diff suppressed because it is too large
Load diff
10
src/view.c
10
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
96
src/xdg.c
96
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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue