From 532656ad5b47d4326f53953698796275a3f733e1 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Fri, 11 Feb 2022 23:12:45 +0000 Subject: [PATCH] Use wlroots scene-graph API Move xdg-shell and xwayland-shell surfaces to new API Also render alt-tab on-screen-display by converting cairo-surface to wlr_buffer --- include/labwc.h | 60 +-- src/cursor.c | 91 ++-- src/damage.c | 16 - src/desktop.c | 172 +------ src/keyboard.c | 3 + src/meson.build | 2 - src/osd.c | 25 +- src/output.c | 956 +-------------------------------------- src/server.c | 12 +- src/subsurface.c | 36 -- src/view-child.c | 42 -- src/view.c | 42 +- src/xdg-popup.c | 74 +-- src/xdg.c | 81 ++-- src/xwayland-unmanaged.c | 22 + src/xwayland.c | 20 +- 16 files changed, 189 insertions(+), 1465 deletions(-) delete mode 100644 src/subsurface.c delete mode 100644 src/view-child.c diff --git a/include/labwc.h b/include/labwc.h index 2747aa9e..439ddff8 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -24,9 +25,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -111,6 +112,8 @@ struct seat { struct wl_listener idle_inhibitor_create; }; +struct lab_data_buffer; + struct server { struct wl_display *wl_display; struct wlr_renderer *renderer; @@ -137,6 +140,10 @@ struct server { struct wl_list unmanaged_surfaces; struct seat seat; + struct wlr_scene *scene; + + /* Tree for all non-layer xdg/xwayland-shell surfaces */ + struct wlr_scene_tree *view_tree; /* cursor interactive */ enum input_mode input_mode; @@ -145,6 +152,8 @@ struct server { struct wlr_box grab_box; uint32_t resize_edges; + struct wlr_scene_tree *osd_tree; + struct wl_list outputs; struct wl_listener new_output; struct wlr_output_layout *output_layout; @@ -172,14 +181,14 @@ struct output { struct wl_list link; /* server::outputs */ struct server *server; struct wlr_output *wlr_output; - struct wlr_output_damage *damage; + struct wlr_scene_output *scene_output; struct wl_list layers[4]; struct wlr_box usable_area; - struct wlr_texture *osd; + + struct lab_data_buffer *osd_buffer; struct wl_listener destroy; - struct wl_listener damage_frame; - struct wl_listener damage_destroy; + struct wl_listener frame; }; enum view_type { @@ -192,10 +201,6 @@ enum view_type { struct view_impl { void (*configure)(struct view *view, struct wlr_box geo); void (*close)(struct view *view); - void (*for_each_popup_surface)(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); const char *(*get_string_prop)(struct view *view, const char *prop); void (*map)(struct view *view); void (*move)(struct view *view, double x, double y); @@ -226,6 +231,7 @@ struct view { #endif }; struct wlr_surface *surface; + struct wlr_scene_node *scene_node; bool mapped; bool been_mapped; @@ -296,7 +302,6 @@ struct view { struct wl_listener set_app_id; /* class on xwayland */ struct wl_listener set_decorations; /* xwayland only */ struct wl_listener new_popup; /* xdg-shell only */ - struct wl_listener new_subsurface; /* xdg-shell only */ }; #if HAVE_XWAYLAND @@ -314,29 +319,6 @@ struct xwayland_unmanaged { }; #endif -struct view_child { - struct wlr_surface *surface; - struct view *parent; - struct wl_listener commit; - struct wl_listener new_subsurface; -}; - -struct view_subsurface { - struct view_child view_child; - struct wlr_subsurface *subsurface; - struct wl_listener destroy; -}; - -struct xdg_popup { - struct view_child view_child; - struct wlr_xdg_popup *wlr_popup; - - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener new_popup; -}; - struct constraint { struct seat *seat; struct wlr_pointer_constraint_v1 *constraint; @@ -361,12 +343,6 @@ void xwayland_unmanaged_create(struct server *server, struct wlr_xwayland_surface *xsurface); #endif -void view_child_init(struct view_child *child, struct view *view, - struct wlr_surface *wlr_surface); -void view_child_finish(struct view_child *child); -void view_subsurface_create(struct view *view, - struct wlr_subsurface *wlr_subsurface); - void view_set_activated(struct view *view, bool activated); void view_close(struct view *view); struct border view_border(struct view *view); @@ -393,10 +369,6 @@ void view_toggle_decorations(struct view *view); void view_set_decorations(struct view *view, bool decorations); void view_toggle_fullscreen(struct view *view); void view_adjust_for_layout_change(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_surface(struct view *view, - wlr_surface_iterator_func_t iterator, void *data); void view_discover_output(struct view *view); void view_move_to_edge(struct view *view, const char *direction); void view_snap_to_edge(struct view *view, const char *direction); @@ -503,7 +475,7 @@ void server_init(struct server *server); void server_start(struct server *server); void server_finish(struct server *server); -/* update onscreen display 'alt-tab' texture */ +/* update onscreen display 'alt-tab' buffer */ void osd_update(struct server *server); /* diff --git a/src/cursor.c b/src/cursor.c index 8e3227c7..37668dcf 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -12,25 +12,25 @@ #include "ssd.h" #include "config/mousebind.h" -void -cursor_rebase(struct seat *seat, uint32_t time_msec) -{ - double sx, sy; - struct wlr_surface *surface; - enum ssd_part_type view_area = LAB_SSD_NONE; - - desktop_surface_and_view_at(seat->server, seat->cursor->x, - seat->cursor->y, &surface, &sx, &sy, &view_area); - - if (surface) { - wlr_seat_pointer_notify_clear_focus(seat->seat); - wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(seat->seat, time_msec, sx, sy); - } else { - cursor_set(seat, "left_ptr"); - wlr_seat_pointer_notify_clear_focus(seat->seat); - } -} +// void +// cursor_rebase(struct seat *seat, uint32_t time_msec) +// { +// double sx, sy; +// struct wlr_surface *surface; +// enum ssd_part_type view_area = LAB_SSD_NONE; +// +// desktop_surface_and_view_at(seat->server, seat->cursor->x, +// seat->cursor->y, &surface, &sx, &sy, &view_area); +// +// if (surface) { +// wlr_seat_pointer_notify_clear_focus(seat->seat); +// wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy); +// wlr_seat_pointer_notify_motion(seat->seat, time_msec, sx, sy); +// } else { +// cursor_set(seat, "left_ptr"); +// wlr_seat_pointer_notify_clear_focus(seat->seat); +// } +// } static void request_cursor_notify(struct wl_listener *listener, void *data) @@ -170,23 +170,6 @@ input_inhibit_blocks_surface(struct seat *seat, struct wl_resource *resource) inhibiting_client != wl_resource_get_client(resource); } -static struct output * -get_output(struct server *server, struct wlr_cursor *cursor) -{ - struct wlr_output *wlr_output = wlr_output_layout_output_at( - server->output_layout, cursor->x, cursor->y); - return output_from_wlr_output(server, wlr_output); -} - -static void -damage_whole_current_output(struct server *server) -{ - struct output *output = get_output(server, server->seat.cursor); - if (output) { - wlr_output_damage_add_whole(output->damage); - } -} - static void process_cursor_motion(struct server *server, uint32_t time) { @@ -278,12 +261,12 @@ process_cursor_motion(struct server *server, uint32_t time) if (ssd_is_button(view_area)) { if (last_button_hover != view_area) { /* Cursor entered new button area */ - damage_whole_current_output(server); + //damage_whole_current_output(server); last_button_hover = view_area; } } else if (last_button_hover != LAB_SSD_NONE) { /* Cursor left button area */ - damage_whole_current_output(server); + //damage_whole_current_output(server); last_button_hover = LAB_SSD_NONE; } @@ -639,7 +622,7 @@ cursor_button(struct wl_listener *listener, void *data) server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; server->grabbed_view = NULL; } - cursor_rebase(&server->seat, event->time_msec); +// cursor_rebase(&server->seat, event->time_msec); } /* Handle _release_ on root window */ @@ -657,24 +640,24 @@ cursor_button(struct wl_listener *listener, void *data) menu_action_selected(server, server->windowmenu); } server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; - cursor_rebase(&server->seat, event->time_msec); +// cursor_rebase(&server->seat, event->time_msec); return; } /* Handle _press_ on a layer surface */ - if (!view && surface) { - if (!wlr_surface_is_layer_surface(surface)) { - return; - } - struct wlr_layer_surface_v1 *layer = - wlr_layer_surface_v1_from_wlr_surface(surface); - if (layer->current.keyboard_interactive) { - seat_set_focus_layer(&server->seat, layer); - } - wlr_seat_pointer_notify_button(seat->seat, event->time_msec, - event->button, event->state); - return; - } +// if (!view && surface) { +// if (!wlr_surface_is_layer_surface(surface)) { +// return; +// } +// struct wlr_layer_surface_v1 *layer = +// wlr_layer_surface_v1_from_wlr_surface(surface); +// if (layer->current.keyboard_interactive) { +// seat_set_focus_layer(&server->seat, layer); +// } +// wlr_seat_pointer_notify_button(seat->seat, event->time_msec, +// event->button, event->state); +// return; +// } /* Handle _press_ on root window */ if (!view) { @@ -721,7 +704,7 @@ cursor_axis(struct wl_listener *listener, void *data) wlr_idle_notify_activity(seat->wlr_idle, seat->seat); /* Notify the client with pointer focus of the axis event. */ - cursor_rebase(seat, event->time_msec); +// cursor_rebase(seat, event->time_msec); wlr_seat_pointer_notify_axis(seat->seat, event->time_msec, event->orientation, event->delta, event->delta_discrete, event->source); diff --git a/src/damage.c b/src/damage.c index 3a1e52c6..983ff428 100644 --- a/src/damage.c +++ b/src/damage.c @@ -4,30 +4,14 @@ 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 9d80da0f..19881f18 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -255,179 +255,23 @@ desktop_focus_topmost_mapped_view(struct server *server) desktop_move_to_front(view); } -static bool -_view_at(struct view *view, double lx, double ly, struct wlr_surface **surface, - double *sx, double *sy) -{ - /* - * XDG toplevels may have nested surfaces, such as popup windows for - * context menus or tooltips. This function tests if any of those are - * underneath the coordinates lx and ly (in output Layout Coordinates). - * If so, it sets the surface pointer to that wlr_surface and the sx and - * sy coordinates to the coordinates relative to that surface's top-left - * corner. - */ - double view_sx = lx - view->x; - double view_sy = ly - view->y; - double _sx, _sy; - struct wlr_surface *_surface = NULL; - - switch (view->type) { - case LAB_XDG_SHELL_VIEW: - _surface = wlr_xdg_surface_surface_at( - view->xdg_surface, view_sx, view_sy, &_sx, &_sy); - break; -#if HAVE_XWAYLAND - case LAB_XWAYLAND_VIEW: - _surface = wlr_surface_surface_at(view->surface, view_sx, - view_sy, &_sx, &_sy); - break; -#endif - } - - if (_surface) { - *sx = _sx; - *sy = _sy; - *surface = _surface; - return true; - } - return false; -} - -static struct -wlr_surface *layer_surface_at(struct wl_list *layer, double ox, double oy, - double *sx, double *sy) -{ - struct lab_layer_surface *surface; - wl_list_for_each_reverse(surface, layer, link) { - double _sx = ox - surface->geo.x; - double _sy = oy - surface->geo.y; - struct wlr_surface *wlr_surface; - wlr_surface = wlr_layer_surface_v1_surface_at( - surface->layer_surface, _sx, _sy, sx, sy); - if (wlr_surface) { - return wlr_surface; - } - } - return NULL; -} - -static bool -surface_is_xdg_popup(struct wlr_surface *surface) -{ - if (wlr_surface_is_xdg_surface(surface)) { - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_from_wlr_surface(surface); - return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP; - } - return false; -} - -static struct wlr_surface * -layer_surface_popup_at(struct output *output, struct wl_list *layer, - double ox, double oy, double *sx, double *sy) -{ - struct lab_layer_surface *lab_layer; - wl_list_for_each_reverse(lab_layer, layer, link) { - double _sx = ox - lab_layer->geo.x; - double _sy = oy - lab_layer->geo.y; - struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( - lab_layer->layer_surface, _sx, _sy, sx, sy); - if (sub && surface_is_xdg_popup(sub)) { - return sub; - } - } - return NULL; -} - struct view * desktop_surface_and_view_at(struct server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy, enum ssd_part_type *view_area) { - struct wlr_output *wlr_output = wlr_output_layout_output_at( - server->output_layout, lx, ly); - struct output *output = output_from_wlr_output(server, wlr_output); + struct wlr_scene_node *node = + wlr_scene_node_at(&server->scene->node, lx, ly, sx, sy); - if (!output) { + if (!node || node->type != WLR_SCENE_NODE_SURFACE) { return NULL; } - - double ox = lx, oy = ly; - wlr_output_layout_output_coords(output->server->output_layout, - wlr_output, &ox, &oy); - - /* Overlay-layer */ - *surface = layer_surface_at( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - ox, oy, sx, sy); - if (*surface) { - return NULL; + *surface = wlr_scene_surface_from_node(node)->surface; + while (node && !node->data) { + node = node->parent; } - - /* Check all layer popups */ - *surface = layer_surface_popup_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - ox, oy, sx, sy); - if (*surface) { - return NULL; - } - *surface = layer_surface_popup_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - ox, oy, sx, sy); - if (*surface) { - return NULL; - } - *surface = layer_surface_popup_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - ox, oy, sx, sy); - if (*surface) { - return NULL; - } - - /* Top-layer */ - *surface = layer_surface_at( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - ox, oy, sx, sy); - if (*surface) { - return NULL; - } - - struct view *view; - wl_list_for_each (view, &server->views, link) { - if (!view->mapped) { - continue; - } - - /* This ignores server-side deco */ - if (_view_at(view, lx, ly, surface, sx, sy)) { - *view_area = LAB_SSD_CLIENT; - return view; - } - if (!view->ssd.enabled) { - continue; - } - - /* Now, let's deal with the server-side deco */ - *view_area = ssd_at(view, lx, ly); - if (*view_area != LAB_SSD_NONE) { - return view; - } - } - - *surface = layer_surface_at( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - ox, oy, sx, sy); - if (*surface) { - return NULL; - } - *surface = layer_surface_at( - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - ox, oy, sx, sy); - if (*surface) { - return NULL; - } - return NULL; + assert(node); + return node->data; } struct view * diff --git a/src/keyboard.c b/src/keyboard.c index 9b1bf846..00e0ce47 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -2,6 +2,7 @@ #include #include #include "action.h" +#include "buffer.h" #include "key-state.h" #include "labwc.h" @@ -49,6 +50,8 @@ keyboard_modifiers_notify(struct wl_listener *listener, void *data) server->cycle_view); desktop_move_to_front(server->cycle_view); server->cycle_view = NULL; + wlr_scene_node_set_enabled( + &server->osd_tree->node, false); } } diff --git a/src/meson.build b/src/meson.build index 536b621a..0bce7cd5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,10 +16,8 @@ labwc_sources = files( 'seat.c', 'server.c', 'ssd.c', - 'subsurface.c', 'theme.c', 'view.c', - 'view-child.c', 'view-impl.c', 'xdg.c', 'xdg-deco.c', diff --git a/src/osd.c b/src/osd.c index f2a54967..f8b1ef0e 100644 --- a/src/osd.c +++ b/src/osd.c @@ -4,6 +4,7 @@ #include #include #include +#include "buffer.h" #include "common/buf.h" #include "common/font.h" #include "config/rcxml.h" @@ -76,7 +77,6 @@ get_osd_height(struct wl_list *views) void osd_update(struct server *server) { - struct wlr_renderer *renderer = server->renderer; struct theme *theme = server->theme; struct output *output; @@ -179,18 +179,21 @@ osd_update(struct server *server) g_object_unref(layout); - /* convert to wlr_texture */ cairo_surface_flush(surf); unsigned char *data = cairo_image_surface_get_data(surf); - struct wlr_texture *texture = wlr_texture_from_pixels(renderer, - DRM_FORMAT_ARGB8888, cairo_image_surface_get_stride(surf), - w, h, data); - - cairo_destroy(cairo); - cairo_surface_destroy(surf); - if (output->osd) { - wlr_texture_destroy(output->osd); + if (output->osd_buffer) { + buffer_drop(output->osd_buffer); } - output->osd = texture; + output->osd_buffer = buffer_create(DRM_FORMAT_ARGB8888, + cairo_image_surface_get_stride(surf), w, h, data); + + cairo_surface_destroy(surf); + + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create( + &server->osd_tree->node, &output->osd_buffer->base); + + /* TODO: set position properly */ + wlr_scene_node_set_position(&scene_buffer->node, 10, 10); + wlr_scene_node_set_enabled(&server->osd_tree->node, true); } } diff --git a/src/output.c b/src/output.c index 9c40fcd5..fc69a294 100644 --- a/src/output.c +++ b/src/output.c @@ -9,949 +9,31 @@ #define _POSIX_C_SOURCE 200809L #include "config.h" #include +#include #include #include #include #include +#include "buffer.h" #include "labwc.h" #include "layers.h" #include "menu/menu.h" #include "ssd.h" #include "theme.h" -#define DEBUG (0) - -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; - struct view *view; - double ox, oy; - int width, height; -}; - -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 -output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy, - void *user_data) -{ - struct surface_iterator_data *data = user_data; - struct output *output = data->output; - if (!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, - }; - assert(surface); - 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 -scissor_output(struct wlr_output *output, pixman_box32_t *rect) -{ - struct wlr_renderer *renderer = output->renderer; - - struct wlr_box box = { - .x = rect->x1, - .y = rect->y1, - .width = rect->x2 - rect->x1, - .height = rect->y2 - rect->y1, - }; - - 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_fbox *src_box, const struct wlr_box *dst_box, - const float matrix[static 9]) -{ - struct wlr_renderer *renderer = wlr_output->renderer; - - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y, - dst_box->width, dst_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]); - const float alpha = 1.0f; - if (src_box != NULL) { - wlr_render_subtexture_with_matrix(renderer, texture, src_box, matrix, alpha); - } else { - wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); - } - } - -damage_finish: - pixman_region32_fini(&damage); -} - -static void -render_surface_iterator(struct output *output, struct wlr_surface *surface, - struct wlr_box *_box, void *user_data) -{ - 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; - } - - struct wlr_fbox src_box; - wlr_surface_get_buffer_source_box(surface, &src_box); - - struct wlr_box proj_box = *_box; - scale_box(&proj_box, wlr_output->scale); - - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &proj_box, transform, 0.0, - wlr_output->transform_matrix); - - struct wlr_box dst_box = *_box; - scale_box(&dst_box, wlr_output->scale); - - render_texture(wlr_output, output_damage, texture, &src_box, &dst_box, matrix); -} - -void -output_drag_icon_for_each_surface(struct output *output, struct seat *seat, - surface_iterator_func_t iterator, void *user_data) -{ - if (!seat->drag_icon || !seat->drag_icon->mapped) { - return; - } - double ox = seat->cursor->x, oy = seat->cursor->y; - wlr_output_layout_output_coords(output->server->output_layout, - output->wlr_output, &ox, &oy); - output_surface_for_each_surface(output, seat->drag_icon->surface, - ox, oy, iterator, user_data); -} - -static void -render_drag_icon(struct output *output, pixman_region32_t *damage) -{ - struct render_data data = { - .damage = damage, - }; - output_drag_icon_for_each_surface(output, &output->server->seat, render_surface_iterator, &data); -} - -#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_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_popup_surface(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; - struct wlr_surface *surface = wlr_layer_surface_v1->surface; - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .view = NULL, - .ox = layer_surface->geo.x, - .oy = layer_surface->geo.y, - .width = surface->current.width, - .height = surface->current.height, - }; - wlr_layer_surface_v1_for_each_surface(wlr_layer_surface_v1, - output_for_each_surface_iterator, &data); - } -} - -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); - output_drag_icon_for_each_surface(output, &output->server->seat, 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_output->renderer; - - struct wlr_box box; - memcpy(&box, _box, sizeof(struct wlr_box)); - - double ox = 0, oy = 0; - wlr_output_layout_output_coords(output->server->output_layout, - output->wlr_output, &ox, &oy); - box.x += ox; - box.y += oy; - scale_box(&box, wlr_output->scale); - - 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 -shrink(struct wlr_box *box, int size) -{ - box->x += size; - box->y += size; - box->width -= 2 * size; - box->height -= 2 * size; -} - -static void -render_cycle_box(struct output *output, pixman_region32_t *output_damage, - struct view *view) -{ - struct wlr_box box = { - .x = view->x, - .y = view->y, - .width = view->w, - .height = view->h, - }; - box.x -= view->margin.left; - box.y -= view->margin.top; - box.width += view->margin.left + view->margin.right; - box.height += view->margin.top + view->margin.bottom; - box.x += view->padding.left; - box.y += view->padding.top; - - 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); - render_rect_unfilled(output, output_damage, &box, black); - } - shrink(&box, 1); - render_rect_unfilled(output, output_damage, &box, white); -} - -static void -render_icon(struct output *output, pixman_region32_t *output_damage, - struct wlr_box *box, struct wlr_texture *texture) -{ - /* centre-align icon if smaller than designated box */ - struct wlr_box button = { - .width = texture->width, - .height = texture->height, - }; - if (box->width > button.width) { - button.x = box->x + (box->width - button.width) / 2; - } else { - button.x = box->x; - button.width = box->width; - } - if (box->height > button.height) { - button.y = box->y + (box->height - button.height) / 2; - } else { - button.y = box->y; - button.height = box->height; - } - - double ox = 0, oy = 0; - wlr_output_layout_output_coords(output->server->output_layout, - output->wlr_output, &ox, &oy); - button.x += ox; - button.y += oy; - scale_box(&button, output->wlr_output->scale); - - float matrix[9]; - wlr_matrix_project_box(matrix, &button, WL_OUTPUT_TRANSFORM_NORMAL, 0, - output->wlr_output->transform_matrix); - render_texture(output->wlr_output, output_damage, texture, NULL, &button, - matrix); -} - -void -render_texture_helper(struct output *output, pixman_region32_t *output_damage, - struct wlr_box *_box, struct wlr_texture *texture) -{ - if (!texture) { - return; - } - struct wlr_box box; - memcpy(&box, _box, sizeof(struct wlr_box)); - - double ox = 0, oy = 0; - wlr_output_layout_output_coords(output->server->output_layout, - output->wlr_output, &ox, &oy); - box.x += ox; - box.y += oy; - scale_box(&box, output->wlr_output->scale); - - float matrix[9]; - wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, - output->wlr_output->transform_matrix); - render_texture(output->wlr_output, output_damage, texture, NULL, &box, - matrix); -} - -static void -render_osd(struct output *output, pixman_region32_t *damage, - struct server *server) -{ - /* show on screen display (osd) on all outputs */ - struct output *o; - struct wlr_output_layout *layout = server->output_layout; - struct wlr_output_layout_output *ol_output; - wl_list_for_each(o, &server->outputs, link) { - ol_output = wlr_output_layout_get(layout, o->wlr_output); - if (!ol_output) { - continue; - } - - if (!output->osd) { - continue; - } - struct wlr_box box = { - .x = ol_output->x + o->wlr_output->width - / 2, - .y = ol_output->y + o->wlr_output->height - / 2, - .width = output->osd->width, - .height = output->osd->height, - }; - box.x -= box.width / 2; - box.y -= box.height / 2; - - double ox = 0, oy = 0; - wlr_output_layout_output_coords(output->server->output_layout, - output->wlr_output, &ox, &oy); - box.x += ox; - box.y += oy; - float matrix[9]; - wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, - 0, output->wlr_output->transform_matrix); - render_texture(o->wlr_output, damage, output->osd, NULL, &box, - matrix); - } -} - -static void -render_deco(struct view *view, struct output *output, - pixman_region32_t *output_damage) -{ - if (!view->ssd.enabled || view->fullscreen) { - return; - } - - struct wlr_seat *seat = view->server->seat.seat; - bool focused = view->surface == seat->keyboard_state.focused_surface; - - /* render texture or rectangle */ - struct ssd_part *part; - wl_list_for_each_reverse(part, &view->ssd.parts, link) { - if (part->texture.active && *(part->texture.active)) { - struct wlr_texture *texture = focused ? - *(part->texture.active) : - *(part->texture.inactive); - render_texture_helper(output, output_damage, &part->box, - texture); - } else if (part->color.active && part->color.inactive) { - float *color = focused ? - part->color.active : - part->color.inactive; - render_rect(output, output_damage, &part->box, color); - } - } - - /* button background */ - struct wlr_cursor *cur = view->server->seat.cursor; - enum ssd_part_type type = ssd_at(view, cur->x, cur->y); - struct wlr_box box = ssd_visible_box(view, type); - if (ssd_is_button(type) && - wlr_box_contains_point(&box, cur->x, cur->y)) { - float *color = (float[4]) { 0.5, 0.5, 0.5, 0.5 }; - render_rect(output, output_damage, &box, color); - } - - /* buttons */ - struct theme *theme = view->server->theme; - if (view->surface == seat->keyboard_state.focused_surface) { - box = ssd_visible_box(view, LAB_SSD_BUTTON_CLOSE); - render_icon(output, output_damage, &box, - theme->xbm_close_active_unpressed); - box = ssd_visible_box(view, LAB_SSD_BUTTON_MAXIMIZE); - render_icon(output, output_damage, &box, - theme->xbm_maximize_active_unpressed); - box = ssd_visible_box(view, LAB_SSD_BUTTON_ICONIFY); - render_icon(output, output_damage, &box, - theme->xbm_iconify_active_unpressed); - box = ssd_visible_box(view, LAB_SSD_BUTTON_WINDOW_MENU); - render_icon(output, output_damage, &box, - theme->xbm_menu_active_unpressed); - } else { - box = ssd_visible_box(view, LAB_SSD_BUTTON_CLOSE); - render_icon(output, output_damage, &box, - theme->xbm_close_inactive_unpressed); - box = ssd_visible_box(view, LAB_SSD_BUTTON_MAXIMIZE); - render_icon(output, output_damage, &box, - theme->xbm_maximize_inactive_unpressed); - box = ssd_visible_box(view, LAB_SSD_BUTTON_ICONIFY); - render_icon(output, output_damage, &box, - theme->xbm_iconify_inactive_unpressed); - box = ssd_visible_box(view, LAB_SSD_BUTTON_WINDOW_MENU); - render_icon(output, output_damage, &box, - theme->xbm_menu_inactive_unpressed); - } -} - -static void -render_menu(struct output *output, pixman_region32_t *damage, struct menu *menu) -{ - if (!menu->visible) { - return; - } - struct server *server = output->server; - struct theme *theme = server->theme; - 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); - - /* background */ - render_rect(output, damage, &menu->box, theme->menu_items_bg_color); - - /* items */ - struct menuitem *menuitem; - wl_list_for_each (menuitem, &menu->menuitems, link) { - struct wlr_box box = { - .x = menuitem->box.x + menuitem->texture.offset_x + ox, - .y = menuitem->box.y + menuitem->texture.offset_y + oy, - .width = menuitem->texture.active->width, - .height = menuitem->texture.active->height, - }; - scale_box(&box, output->wlr_output->scale); - wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, - 0, output->wlr_output->transform_matrix); - if (menuitem->selected) { - render_rect(output, damage, &menuitem->box, - theme->menu_items_active_bg_color); - render_texture(output->wlr_output, damage, - menuitem->texture.active, NULL, &box, matrix); - } else { - render_texture(output->wlr_output, damage, - menuitem->texture.inactive, NULL, &box, matrix); - } - /* render submenus */ - if (menuitem->submenu) { - render_menu(output, damage, menuitem->submenu); - } - } -} - -static void -output_layer_for_each_popup_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; - struct wlr_surface *surface = wlr_layer_surface_v1->surface; - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .view = NULL, - .ox = layer_surface->geo.x, - .oy = layer_surface->geo.y, - .width = surface->current.width, - .height = surface->current.height, - }; - wlr_layer_surface_v1_for_each_popup_surface(wlr_layer_surface_v1, - output_for_each_surface_iterator, &data); - } -} - -static void -render_layer_popups(struct output *output, pixman_region32_t *damage, - struct wl_list *layer_surfaces) -{ - struct render_data data = { - .damage = damage, - }; - output_layer_for_each_popup_surface(output, layer_surfaces, - render_surface_iterator, &data); -} - -void -output_layer_for_each_surface_toplevel(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); - } -} - -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_view_toplevels(struct view *view, struct output *output, - pixman_region32_t *damage) -{ - 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); -} - -static void -render_view_popups(struct view *view, struct output *output, - pixman_region32_t *damage) -{ - struct render_data data = { - .damage = damage, - }; - output_view_for_each_popup_surface(output, view, - render_surface_iterator, &data); -} - -void -output_render(struct output *output, pixman_region32_t *damage) -{ - struct server *server = output->server; - struct wlr_output *wlr_output = output->wlr_output; - - struct wlr_renderer *renderer = wlr_output->renderer; - if (!renderer) { - wlr_log(WLR_DEBUG, "no renderer"); - return; - } - - /* Calls glViewport and some other GL sanity checks */ - wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); - - if (!pixman_region32_not_empty(damage)) { - goto renderer_end; - } - -#if 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, &server->views, link) { - if (!view->mapped) { - continue; - } - render_deco(view, output, damage); - render_view_toplevels(view, output, damage); - render_view_popups(view, output, damage); - } - -#if HAVE_XWAYLAND - render_unmanaged(output, damage, &output->server->unmanaged_surfaces); -#endif - - /* 'alt-tab' border */ - if (output->server->cycle_view) { - /* If the 'cycle_preview_contents' option is set in - * rc.xml, render the contents of the cycle_view over - * all other views (except for the OSD) - */ - if (rc.cycle_preview_contents) { - render_deco(output->server->cycle_view, output, damage); - render_view_toplevels(output->server->cycle_view, output, damage); - render_view_popups(output->server->cycle_view, output, damage); - } - - render_cycle_box(output, damage, output->server->cycle_view); - render_osd(output, damage, output->server); - } - - render_drag_icon(output, damage); - - render_layer_toplevel(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - render_layer_popups(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer_popups(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - render_layer_popups(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - - render_layer_toplevel(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_layer_popups(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - - if (output->server->input_mode == LAB_INPUT_STATE_MENU) { - render_menu(output, damage, server->rootmenu); - render_menu(output, damage, server->windowmenu); - } - -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); - - int output_width, output_height; - wlr_output_transformed_resolution(wlr_output, &output_width, - &output_height); - - 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); - -#if DEBUG - pixman_region32_union_rect(&frame_damage, &frame_damage, 0, 0, - output_width, output_height); -#endif - - wlr_output_set_damage(wlr_output, &frame_damage); - pixman_region32_fini(&frame_damage); - - if (!wlr_output_commit(wlr_output)) { - wlr_log(WLR_ERROR, "could not commit output"); - } -} - -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); - } -} - -void -output_damage_surface(struct output *output, struct wlr_surface *surface, - double lx, double ly, bool whole) +output_frame_notify(struct wl_listener *listener, void *data) { + struct output *output = wl_container_of(listener, output, frame); 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); -} + wlr_scene_output_commit(output->scene_output); -static void -output_damage_frame_notify(struct wl_listener *listener, void *data) -{ - 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_damage_destroy_notify(struct wl_listener *listener, void *data) -{ - struct output *output = wl_container_of(listener, output, damage_destroy); - wl_list_remove(&output->damage_frame.link); - wl_list_remove(&output->damage_destroy.link); + struct timespec now = { 0 }; + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_scene_output_send_frame_done(output->scene_output, &now); } static void @@ -959,6 +41,7 @@ output_destroy_notify(struct wl_listener *listener, void *data) { struct output *output = wl_container_of(listener, output, destroy); wl_list_remove(&output->link); + wl_list_remove(&output->frame.link); wl_list_remove(&output->destroy.link); } @@ -1018,18 +101,14 @@ new_output_notify(struct wl_listener *listener, void *data) output->wlr_output = wlr_output; wlr_output->data = output; output->server = server; - output->damage = wlr_output_damage_create(wlr_output); wlr_output_effective_resolution(wlr_output, &output->usable_area.width, &output->usable_area.height); 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); + output->frame.notify = output_frame_notify; + wl_signal_add(&wlr_output->events.frame, &output->frame); wl_list_init(&output->layers[0]); wl_list_init(&output->layers[1]); @@ -1046,9 +125,17 @@ new_output_notify(struct wl_listener *listener, void *data) wlr_output_enable_adaptive_sync(wlr_output, true); } - output->osd = NULL; - wlr_output_layout_add_auto(server->output_layout, wlr_output); + + /* TODO: check this makes sense */ + struct wlr_scene_output *scene_output; + wl_list_for_each (scene_output, &output->server->scene->outputs, link) { + if (scene_output->output == wlr_output) { + output->scene_output = scene_output; + break; + } + } + assert(output->scene_output); } void @@ -1117,6 +204,7 @@ output_config_apply(struct server *server, bool need_to_remove = !head->state.enabled && o->enabled; if (need_to_remove) { + /* TODO: should we output->scene_output = NULL; ?? */ wlr_output_layout_remove(server->output_layout, o); } diff --git a/src/server.c b/src/server.c index 450b71e8..fd59599a 100644 --- a/src/server.c +++ b/src/server.c @@ -216,6 +216,17 @@ server_init(struct server *server) wl_list_init(&server->views); wl_list_init(&server->unmanaged_surfaces); + output_init(server); + + server->scene = wlr_scene_create(); + if (!server->scene) { + wlr_log(WLR_ERROR, "unable to create scene"); + exit(EXIT_FAILURE); + } + server->view_tree = wlr_scene_tree_create(&server->scene->node); + server->osd_tree = wlr_scene_tree_create(&server->scene->node); + wlr_scene_attach_output_layout(server->scene, server->output_layout); + /* * Create some hands-off wlroots interfaces. The compositor is * necessary for clients to allocate surfaces and the data device @@ -249,7 +260,6 @@ server_init(struct server *server) */ wlr_primary_selection_v1_device_manager_create(server->wl_display); - output_init(server); seat_init(server); /* Init xdg-shell */ diff --git a/src/subsurface.c b/src/subsurface.c deleted file mode 100644 index 79866355..00000000 --- a/src/subsurface.c +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2020 the sway authors - * This file is only needed in support of tracking damage - */ - -#include "labwc.h" - -static void -subsurface_handle_destroy(struct wl_listener *listener, void *data) -{ - struct view_subsurface *subsurface = wl_container_of(listener, - subsurface, destroy); - struct view_child *view_child = (struct view_child *)subsurface; - if (!view_child) { - return; - } - wl_list_remove(&subsurface->destroy.link); - view_child_finish(&subsurface->view_child); - free(subsurface); -} - -void -view_subsurface_create(struct view *view, struct wlr_subsurface *wlr_subsurface) -{ - struct view_subsurface *subsurface = - calloc(1, sizeof(struct view_subsurface)); - if (!subsurface) { - return; - } - view_child_init(&subsurface->view_child, view, wlr_subsurface->surface); - subsurface->subsurface = wlr_subsurface; - - subsurface->destroy.notify = subsurface_handle_destroy; - wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); -} diff --git a/src/view-child.c b/src/view-child.c deleted file mode 100644 index 462a53a4..00000000 --- a/src/view-child.c +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2020 the sway authors - * This file is only needed in support of tracking damage - */ - -#include "labwc.h" - -static void -view_child_handle_commit(struct wl_listener *listener, void *data) -{ - struct view_child *child = wl_container_of(listener, child, commit); - damage_all_outputs(child->parent->server); -} - -static void -view_child_handle_new_subsurface(struct wl_listener *listener, void *data) -{ - struct view_child *child; - child = wl_container_of(listener, child, new_subsurface); - struct wlr_subsurface *wlr_subsurface = data; - view_subsurface_create(child->parent, wlr_subsurface); -} - -void -view_child_finish(struct view_child *child) -{ - wl_list_remove(&child->commit.link); - wl_list_remove(&child->new_subsurface.link); -} - -void -view_child_init(struct view_child *child, struct view *view, - struct wlr_surface *wlr_surface) -{ - child->parent = view; - child->surface = wlr_surface; - child->commit.notify = view_child_handle_commit; - wl_signal_add(&wlr_surface->events.commit, &child->commit); - child->new_subsurface.notify = view_child_handle_new_subsurface; - wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface); -} diff --git a/src/view.c b/src/view.c index 5587b1dc..9379cdf7 100644 --- a/src/view.c +++ b/src/view.c @@ -31,6 +31,7 @@ view_move(struct view *view, double x, double y) view->impl->move(view, x, y); } view_discover_output(view); + wlr_scene_node_set_position(view->scene_node, view->x, view->y); } void @@ -44,6 +45,7 @@ view_move_resize(struct view *view, struct wlr_box geo) } ssd_update_title(view); view_discover_output(view); + wlr_scene_node_set_position(view->scene_node, view->x, view->y); } #define MIN_VIEW_WIDTH (100) @@ -145,6 +147,7 @@ view_center(struct view *view) if (view_compute_centered_position(view, view->w, view->h, &x, &y)) { view_move(view, x, y); } + wlr_scene_node_set_position(view->scene_node, view->x, view->y); } static void @@ -220,6 +223,7 @@ view_maximize(struct view *view, bool maximize) if (view->fullscreen) { return; } + wlr_scene_node_set_position(view->scene_node, view->x, view->y); if (view->impl->maximize) { view->impl->maximize(view, maximize); } @@ -341,24 +345,6 @@ view_adjust_for_layout_change(struct view *view) } } -void -view_for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, - void *user_data) -{ - if (view->impl->for_each_surface) { - view->impl->for_each_surface(view, iterator, user_data); - } -} - -void -view_for_each_popup_surface(struct view *view, - wlr_surface_iterator_func_t iterator, void *data) -{ - if (view->impl->for_each_popup_surface) { - view->impl->for_each_popup_surface(view, iterator, data); - } -} - struct border view_border(struct view *view) { @@ -371,27 +357,9 @@ view_border(struct view *view) return border; } -static void -surface_enter_for_each_surface(struct wlr_surface *surface, int sx, int sy, - void *user_data) -{ - struct wlr_output *wlr_output = user_data; - wlr_surface_send_enter(surface, wlr_output); -} - -static void -surface_leave_for_each_surface(struct wlr_surface *surface, int sx, int sy, - void *user_data) -{ - struct wlr_output *wlr_output = user_data; - wlr_surface_send_leave(surface, wlr_output); -} - static void view_output_enter(struct view *view, struct wlr_output *wlr_output) { - view_for_each_surface(view, surface_enter_for_each_surface, - wlr_output); if (view->toplevel_handle) { wlr_foreign_toplevel_handle_v1_output_enter( view->toplevel_handle, wlr_output); @@ -401,8 +369,6 @@ view_output_enter(struct view *view, struct wlr_output *wlr_output) static void view_output_leave(struct view *view, struct wlr_output *wlr_output) { - view_for_each_surface(view, surface_leave_for_each_surface, - wlr_output); if (view->toplevel_handle) { wlr_foreign_toplevel_handle_v1_output_leave( view->toplevel_handle, wlr_output); diff --git a/src/xdg-popup.c b/src/xdg-popup.c index de5a925e..731967f2 100644 --- a/src/xdg-popup.c +++ b/src/xdg-popup.c @@ -3,63 +3,17 @@ * Copyright (C) 2020 the sway authors * * This file is only needed in support of - * - tracking damage * - unconstraining XDG popups */ #include "labwc.h" +/* TODO: surely this ought to just move to xdg.c now??? */ static void -xdg_popup_destroy(struct view_child *view_child) +popup_unconstrain(struct view *view, struct wlr_xdg_popup *popup) { - if (!view_child) { - return; - } - struct xdg_popup *popup = (struct xdg_popup *)view_child; - wl_list_remove(&popup->destroy.link); - wl_list_remove(&popup->map.link); - wl_list_remove(&popup->unmap.link); - wl_list_remove(&popup->new_popup.link); - view_child_finish(&popup->view_child); - free(popup); -} - -static void -handle_xdg_popup_map(struct wl_listener *listener, void *data) -{ - struct xdg_popup *popup = wl_container_of(listener, popup, map); - damage_all_outputs(popup->view_child.parent->server); -} - -static void -handle_xdg_popup_unmap(struct wl_listener *listener, void *data) -{ - struct xdg_popup *popup = wl_container_of(listener, popup, unmap); - damage_all_outputs(popup->view_child.parent->server); -} - -static void -handle_xdg_popup_destroy(struct wl_listener *listener, void *data) -{ - struct xdg_popup *popup = wl_container_of(listener, popup, destroy); - struct view_child *view_child = (struct view_child *)popup; - xdg_popup_destroy(view_child); -} - -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_child.parent, wlr_popup); -} - -static void -popup_unconstrain(struct xdg_popup *popup) -{ - struct view *view = popup->view_child.parent; struct server *server = view->server; - struct wlr_box *popup_box = &popup->wlr_popup->geometry; + struct wlr_box *popup_box = &popup->geometry; struct wlr_output_layout *output_layout = server->output_layout; struct wlr_output *wlr_output = wlr_output_layout_output_at( output_layout, view->x + popup_box->x, view->y + popup_box->y); @@ -72,29 +26,11 @@ popup_unconstrain(struct xdg_popup *popup) .width = output_box->width, .height = output_box->height, }; - wlr_xdg_popup_unconstrain_from_box( - popup->wlr_popup, &output_toplevel_box); + wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box); } 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; - view_child_init(&popup->view_child, view, wlr_popup->base->surface); - - popup->destroy.notify = handle_xdg_popup_destroy; - wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); - 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); - - popup_unconstrain(popup); + popup_unconstrain(view, wlr_popup); } diff --git a/src/xdg.c b/src/xdg.c index 02b202e3..9920d3e5 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -3,10 +3,6 @@ #include "labwc.h" #include "ssd.h" -/* - * xdg_popup_create() and view_subsurface_create() are only called for the - * purposes of tracking damage. - */ static void handle_new_xdg_popup(struct wl_listener *listener, void *data) { @@ -15,14 +11,6 @@ handle_new_xdg_popup(struct wl_listener *listener, void *data) xdg_popup_create(view, wlr_popup); } -static void -new_subsurface_notify(struct wl_listener *listener, void *data) -{ - struct view *view = wl_container_of(listener, view, new_subsurface); - struct wlr_subsurface *wlr_subsurface = data; - view_subsurface_create(view, wlr_subsurface); -} - static bool has_ssd(struct view *view) { @@ -222,20 +210,6 @@ xdg_toplevel_view_close(struct view *view) wlr_xdg_toplevel_send_close(view->xdg_surface); } -static void -xdg_toplevel_view_for_each_popup_surface(struct view *view, - wlr_surface_iterator_func_t iterator, void *data) -{ - wlr_xdg_surface_for_each_popup_surface(view->xdg_surface, iterator, data); -} - -static void -xdg_toplevel_view_for_each_surface(struct view *view, - wlr_surface_iterator_func_t iterator, void *data) -{ - wlr_xdg_surface_for_each_surface(view->xdg_surface, iterator, data); -} - static void update_padding(struct view *view) { @@ -352,16 +326,6 @@ xdg_toplevel_view_map(struct view *view) if (!view->maximized && !view->fullscreen) { position_xdg_toplevel_view(view); } - - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &view->surface->current.subsurfaces_below, - current.link) { - view_subsurface_create(view, subsurface); - } - wl_list_for_each(subsurface, &view->surface->current.subsurfaces_above, - current.link) { - view_subsurface_create(view, subsurface); - } view_discover_output(view); view->been_mapped = true; @@ -370,9 +334,6 @@ xdg_toplevel_view_map(struct view *view) view->commit.notify = handle_commit; wl_signal_add(&view->xdg_surface->surface->events.commit, &view->commit); - view->new_subsurface.notify = new_subsurface_notify; - wl_signal_add(&view->surface->events.new_subsurface, - &view->new_subsurface); view_impl_map(view); } @@ -383,8 +344,8 @@ xdg_toplevel_view_unmap(struct view *view) if (view->mapped) { view->mapped = false; damage_all_outputs(view->server); + wlr_scene_node_destroy(view->scene_node); wl_list_remove(&view->commit.link); - wl_list_remove(&view->new_subsurface.link); desktop_focus_topmost_mapped_view(view->server); } } @@ -392,8 +353,6 @@ 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_surface = xdg_toplevel_view_for_each_popup_surface, - .for_each_surface = xdg_toplevel_view_for_each_surface, .get_string_prop = xdg_toplevel_view_get_string_prop, .map = xdg_toplevel_view_map, .move = xdg_toplevel_view_move, @@ -403,15 +362,39 @@ static const struct view_impl xdg_toplevel_view_impl = { .maximize = xdg_toplevel_view_maximize, }; +/* + * We use the following struct user_data pointers: + * - wlr_xdg_surface->data = view + * for the wlr_xdg_toplevel_decoration_v1 implementation + * - wlr_surface->data = scene_node + * to help the popups find their parent nodes + */ void xdg_surface_new(struct wl_listener *listener, void *data) { struct server *server = wl_container_of(listener, server, new_xdg_surface); struct wlr_xdg_surface *xdg_surface = data; - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + + /* + * We must add xdg popups to the scene graph so they get rendered. The + * wlroots scene graph provides a helper for this, but to use it we must + * provide the proper parent scene node of the xdg popup. To enable + * this, we always set the user data field of xdg_surfaces to the + * corresponding scene node. + */ + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + struct wlr_xdg_surface *parent = + wlr_xdg_surface_from_wlr_surface( + xdg_surface->popup->parent); + struct wlr_scene_node *parent_node = parent->surface->data; + xdg_surface->surface->data = + wlr_scene_xdg_surface_create(parent_node, xdg_surface); + /* TODO: unconstrain here rather than in xdg-popup.c? */ return; } + + /* WLR_XDG_SURFACE_ROLE_TOPLEVEL */ wlr_xdg_surface_ping(xdg_surface); struct view *view = calloc(1, sizeof(struct view)); @@ -421,8 +404,20 @@ xdg_surface_new(struct wl_listener *listener, void *data) view->xdg_surface = xdg_surface; wl_list_init(&view->ssd.parts); + view->scene_node = wlr_scene_xdg_surface_create( + &view->server->view_tree->node, view->xdg_surface); + if (!view->scene_node) { + wl_resource_post_no_memory(view->surface->resource); + return; + } + view->scene_node->data = view; + + /* In support of xdg_toplevel_decoration */ xdg_surface->data = view; + /* In support of xdg popups */ + xdg_surface->surface->data = view->scene_node; + view->map.notify = handle_map; wl_signal_add(&xdg_surface->events.map, &view->map); view->unmap.notify = handle_unmap; diff --git a/src/xwayland-unmanaged.c b/src/xwayland-unmanaged.c index b5c5922a..a80b9e6e 100644 --- a/src/xwayland-unmanaged.c +++ b/src/xwayland-unmanaged.c @@ -23,6 +23,22 @@ unmanaged_handle_commit(struct wl_listener *listener, void *data) damage_all_outputs(unmanaged->server); } +static struct view * +parent_view(struct server *server, struct wlr_xwayland_surface *surface) +{ + struct wlr_xwayland_surface *s = surface; + while (s->parent) { + s = s->parent; + } + struct view *view; + wl_list_for_each(view, &server->views, link) { + if (view->surface == s->surface) { + return view; + } + } + return NULL; +} + static void unmanaged_handle_map(struct wl_listener *listener, void *data) { @@ -42,6 +58,12 @@ unmanaged_handle_map(struct wl_listener *listener, void *data) if (wlr_xwayland_or_surface_wants_focus(xsurface)) { seat_focus_surface(&unmanaged->server->seat, xsurface->surface); } + + struct view *view = parent_view(unmanaged->server, xsurface); + struct wlr_scene_node *node = wlr_scene_subsurface_tree_create( + view->scene_node, xsurface->surface); + wlr_scene_node_set_position(node, unmanaged->lx - view->x, + unmanaged->ly - view->y); } static void diff --git a/src/xwayland.c b/src/xwayland.c index a8194562..a8d2f696 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -195,16 +195,6 @@ _close(struct view *view) 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); -} - static const char * get_string_prop(struct view *view, const char *prop) { @@ -265,6 +255,15 @@ map(struct view *view) view->h = view->xwayland_surface->height; } view->surface = view->xwayland_surface->surface; + + view->scene_node = wlr_scene_surface_create( + &view->server->view_tree->node, view->surface); + if (!view->scene_node) { + wl_resource_post_no_memory(view->surface->resource); + return; + } + view->scene_node->data = view; + view->ssd.enabled = want_deco(view); if (view->ssd.enabled) { @@ -338,7 +337,6 @@ set_fullscreen(struct view *view, bool fullscreen) static const struct view_impl xwl_view_impl = { .configure = configure, .close = _close, - .for_each_surface = for_each_surface, .get_string_prop = get_string_prop, .map = map, .move = move,