]> git.mdlowis.com Git - proto/labwc.git/commitdiff
Use wlroots scene-graph API
authorJohan Malm <jgm323@gmail.com>
Fri, 11 Feb 2022 23:12:45 +0000 (23:12 +0000)
committerJohan Malm <jgm323@gmail.com>
Wed, 23 Feb 2022 21:46:48 +0000 (21:46 +0000)
Move xdg-shell and xwayland-shell surfaces to new API

Also render alt-tab on-screen-display by converting cairo-surface to
wlr_buffer

16 files changed:
include/labwc.h
src/cursor.c
src/damage.c
src/desktop.c
src/keyboard.c
src/meson.build
src/osd.c
src/output.c
src/server.c
src/subsurface.c [deleted file]
src/view-child.c [deleted file]
src/view.c
src/xdg-popup.c
src/xdg.c
src/xwayland-unmanaged.c
src/xwayland.c

index 2747aa9ed93640d6fc72e7aa7918fe03c2aa17ed..439ddff8b872deceb64db4e210ce5acccbe39ea3 100644 (file)
@@ -13,6 +13,7 @@
 #include <wlr/render/allocator.h>
 #include <wlr/render/wlr_renderer.h>
 #include <wlr/types/wlr_compositor.h>
+#include <wlr/types/wlr_buffer.h>
 #include <wlr/types/wlr_cursor.h>
 #include <wlr/types/wlr_data_device.h>
 #include <wlr/types/wlr_foreign_toplevel_management_v1.h>
@@ -24,9 +25,9 @@
 #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_management_v1.h>
 #include <wlr/types/wlr_output_layout.h>
+#include <wlr/types/wlr_scene.h>
 #include <wlr/types/wlr_relative_pointer_v1.h>
 #include <wlr/types/wlr_pointer.h>
 #include <wlr/types/wlr_pointer_constraints_v1.h>
@@ -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);
 
 /*
index 8e3227c7504ae64434cbad0d943c64549968fc46..37668dcf81f22042750349030be1e47895acae53 100644 (file)
 #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);
index 3a1e52c6c20b201940097ec9986f8e2bf44ac3fd..983ff428582f76bb8ce2e18e2e40f0a12452b1ca 100644 (file)
@@ -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);
-       }
 }
index 9d80da0f1e00654271dbc92a170277c287a47467..19881f18fad15ff98179b0b468e9872fd595181f 100644 (file)
@@ -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;
-       }
-
-       /* 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;
+       *surface = wlr_scene_surface_from_node(node)->surface;
+       while (node && !node->data) {
+               node = node->parent;
        }
-       return NULL;
+       assert(node);
+       return node->data;
 }
 
 struct view *
index 9b1bf84631927d3d646482eef42a4c45465c7f4f..00e0ce4795168f4c50d73c3e67a153ccb9d9f08f 100644 (file)
@@ -2,6 +2,7 @@
 #include <wlr/backend/multi.h>
 #include <wlr/backend/session.h>
 #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);
                }
        }
 
index 536b621afecd2d16b5b709dfef2a803273409a0e..0bce7cd5f23a7ee097469aea1b095465a2bc0690 100644 (file)
@@ -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',
index f2a549672f44521aa9e7b6df40f19cdc39451672..f8b1ef0e6fe49524fcab49f912bfee9b0223ac5d 100644 (file)
--- a/src/osd.c
+++ b/src/osd.c
@@ -4,6 +4,7 @@
 #include <drm_fourcc.h>
 #include <pango/pangocairo.h>
 #include <wlr/util/log.h>
+#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);
+               if (output->osd_buffer) {
+                       buffer_drop(output->osd_buffer);
+               }
+               output->osd_buffer = buffer_create(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);
-               }
-               output->osd = texture;
+
+               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);
        }
 }
index 9c40fcd567c6eaad64d2333965f1d7852c1f650c..fc69a294af084208bf7863c72c2f1590dc3b95c8 100644 (file)
 #define _POSIX_C_SOURCE 200809L
 #include "config.h"
 #include <assert.h>
+#include <wlr/types/wlr_buffer.h>
 #include <wlr/types/wlr_xdg_output_v1.h>
 #include <wlr/types/wlr_output_damage.h>
 #include <wlr/util/region.h>
 #include <wlr/util/log.h>
+#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)
+output_frame_notify(struct wl_listener *listener, void *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)
-{
-       if (!output->wlr_output->enabled) {
-               return;
-       }
-
-       double ox = lx, oy = ly;
-       wlr_output_layout_output_coords(output->server->output_layout,
-               output->wlr_output, &ox, &oy);
-       output_surface_for_each_surface(output, surface, ox, oy,
-               damage_surface_iterator, &whole);
-}
-
-static void
-output_damage_frame_notify(struct wl_listener *listener, void *data)
-{
-       struct output *output = wl_container_of(listener, output, damage_frame);
-
+       struct output *output = wl_container_of(listener, output, 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);
+       wlr_scene_output_commit(output->scene_output);
 
-       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);
                }
 
index 450b71e825818d26a030e46f86bb7d06ac0aa7f7..fd59599ad5fb72ca23d885f8c8fed922e4efc484 100644 (file)
@@ -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 (file)
index 7986635..0000000
+++ /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 (file)
index 462a53a..0000000
+++ /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);
-}
index 5587b1dce34ce5d79ec20e866b1da853374616b5..9379cdf70960fb826e58902996d712eb69303666 100644 (file)
@@ -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);
index de5a925e92dae44c360d7505a28ef1b72e3bac1f..731967f22eac495f612694204169620d10063238 100644 (file)
@@ -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);
 }
index 02b202e384ec8bb3f1d2a60ba60ede1b7dcbd0a2..9920d3e5af36686782a0bbaf4fd9a1028a93a863 100644 (file)
--- 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;
index b5c5922aa3a795407d0d2357b115e54c978c22d4..a80b9e6e19280c4d6ddb6c448d48c3372bf2694f 100644 (file)
@@ -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
index a8194562238e4880f6ece3ac7bdc9a102de76c40..a8d2f696ab33c542f18606087e00b0c0c9c97b8a 100644 (file)
@@ -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,