diff --git a/output.c b/output.c index 862911e..84b61aa 100644 --- a/output.c +++ b/output.c @@ -100,7 +100,7 @@ output_for_each_surface_iterator(struct wlr_surface *surface, int sx, int sy, vo data->user_iterator(data->output, surface, &box, data->user_data); } -static void +void output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *surface, double ox, double oy, cg_surface_iterator_func_t iterator, void *user_data) @@ -116,7 +116,7 @@ output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *su wlr_surface_for_each_surface(surface, output_for_each_surface_iterator, &data); } -void +static void output_view_for_each_surface(struct cg_output *output, struct cg_view *view, cg_surface_iterator_func_t iterator, void *user_data) { @@ -132,6 +132,49 @@ output_view_for_each_surface(struct cg_output *output, struct cg_view *view, view_for_each_surface(view, output_for_each_surface_iterator, &data); } +void +output_view_for_each_popup(struct cg_output *output, struct cg_view *view, + cg_surface_iterator_func_t iterator, void *user_data) +{ + struct surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .output = output, + .ox = view->lx, + .oy = view->ly, + }; + + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &data.ox, &data.oy); + view_for_each_popup(view, output_for_each_surface_iterator, &data); +} + +void +output_drag_icons_for_each_surface(struct cg_output *output, struct wl_list *drag_icons, + cg_surface_iterator_func_t iterator, void *user_data) +{ + struct cg_drag_icon *drag_icon; + wl_list_for_each(drag_icon, drag_icons, link) { + if (drag_icon->wlr_drag_icon->mapped) { + double ox = drag_icon->lx; + double oy = drag_icon->ly; + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &ox, &oy); + output_surface_for_each_surface(output, drag_icon->wlr_drag_icon->surface, + ox, oy, iterator, user_data); + } + } +} + +static void +output_for_each_surface(struct cg_output *output, cg_surface_iterator_func_t iterator, void *user_data) +{ + struct cg_view *view; + wl_list_for_each_reverse(view, &output->server->views, link) { + output_view_for_each_surface(output, view, iterator, user_data); + } + + output_drag_icons_for_each_surface(output, &output->server->seat->drag_icons, iterator, user_data); +} + struct send_frame_done_data { struct timespec when; }; @@ -187,33 +230,6 @@ output_damage_surface(struct cg_output *output, struct wlr_surface *surface, output_surface_for_each_surface(output, surface, ox, oy, damage_surface_iterator, &whole); } -void -output_drag_icons_for_each_surface(struct cg_output *output, struct wl_list *drag_icons, - cg_surface_iterator_func_t iterator, void *user_data) -{ - struct cg_drag_icon *drag_icon; - wl_list_for_each(drag_icon, drag_icons, link) { - if (drag_icon->wlr_drag_icon->mapped) { - double ox = drag_icon->lx; - double oy = drag_icon->ly; - wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &ox, &oy); - output_surface_for_each_surface(output, drag_icon->wlr_drag_icon->surface, - ox, oy, iterator, user_data); - } - } -} - -static void -output_for_each_surface(struct cg_output *output, cg_surface_iterator_func_t iterator, void *user_data) -{ - struct cg_view *view; - wl_list_for_each_reverse(view, &output->server->views, link) { - output_view_for_each_surface(output, view, iterator, user_data); - } - - output_drag_icons_for_each_surface(output, &output->server->seat->drag_icons, iterator, user_data); -} - static void handle_output_damage_frame(struct wl_listener *listener, void *data) { diff --git a/output.h b/output.h index 608f762..081c9fd 100644 --- a/output.h +++ b/output.h @@ -26,7 +26,10 @@ struct cg_output { typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *user_data); void handle_new_output(struct wl_listener *listener, void *data); -void output_view_for_each_surface(struct cg_output *output, struct cg_view *view, cg_surface_iterator_func_t iterator, void *user_data); +void output_surface_for_each_surface(struct cg_output *output, struct wlr_surface *surface, + double ox, double oy, cg_surface_iterator_func_t iterator, + void *user_data); +void output_view_for_each_popup(struct cg_output *output, struct cg_view *view, cg_surface_iterator_func_t iterator, void *user_data); void output_drag_icons_for_each_surface(struct cg_output *output, struct wl_list *drag_icons, cg_surface_iterator_func_t iterator, void *user_data); void output_damage_surface(struct cg_output *output, struct wlr_surface *surface, double lx, double ly, bool whole); void output_set_window_title(struct cg_output *output, const char *title); diff --git a/render.c b/render.c index b75ad7d..c222b8f 100644 --- a/render.c +++ b/render.c @@ -115,8 +115,32 @@ render_view_toplevels(struct cg_view *view, struct cg_output *output, pixman_reg struct render_data data = { .damage = damage, }; + double ox = view->lx; + double oy = view->ly; + wlr_output_layout_output_coords(output->server->output_layout, output->wlr_output, &ox, &oy); + output_surface_for_each_surface(output, view->wlr_surface, ox, oy, + render_surface_iterator, &data); +} - output_view_for_each_surface(output, view, render_surface_iterator, &data); +static void +render_popup_iterator(struct cg_output *output, struct wlr_surface *surface, + struct wlr_box *box, void *data) +{ + /* Render this popup's surface. */ + render_surface_iterator(output, surface, box, data); + + /* Render this popup's child toplevels. */ + output_surface_for_each_surface(output, surface, box->x, box->y, + render_surface_iterator, data); +} + +static void +render_view_popups(struct cg_view *view, struct cg_output *output, pixman_region32_t *damage) +{ + struct render_data data = { + .damage = damage, + }; + output_view_for_each_popup(output, view, render_popup_iterator, &data); } void @@ -151,8 +175,11 @@ output_render(struct cg_output *output, pixman_region32_t *damage) struct cg_view *view; wl_list_for_each_reverse(view, &server->views, link) { render_view_toplevels(view, output, damage); - // TODO: popups on top view, possibly use focused view for this - // TODO: render only top view, possibly use focused view for this + } + + struct cg_view *focused_view = seat_get_focus(server->seat); + if (focused_view) { + render_view_popups(focused_view, output, damage); } render_drag_icons(output, damage, &server->seat->drag_icons); diff --git a/view.c b/view.c index e22ab04..b19248b 100644 --- a/view.c +++ b/view.c @@ -197,6 +197,15 @@ view_for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator view->impl->for_each_surface(view, iterator, data); } +void +view_for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data) +{ + if (!view->impl->for_each_popup) { + return; + } + view->impl->for_each_popup(view, iterator, data); +} + void view_unmap(struct cg_view *view) { diff --git a/view.h b/view.h index ffbd364..1da861c 100644 --- a/view.h +++ b/view.h @@ -46,6 +46,8 @@ struct cg_view_impl { void (*destroy)(struct cg_view *view); void (*for_each_surface)(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data); + void (*for_each_popup)(struct cg_view *view, wlr_surface_iterator_func_t iterator, + void *data); struct wlr_surface *(*wlr_surface_at)(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y); }; @@ -76,6 +78,7 @@ void view_damage_whole(struct cg_view *view); void view_activate(struct cg_view *view, bool activate); void view_position(struct cg_view *view); void view_for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data); +void view_for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data); void view_unmap(struct cg_view *view); void view_map(struct cg_view *view, struct wlr_surface *surface); void view_destroy(struct cg_view *view); diff --git a/xdg_shell.c b/xdg_shell.c index 3334082..4c6d0ee 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -222,6 +222,13 @@ for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, voi wlr_xdg_surface_for_each_surface(xdg_shell_view->xdg_surface, iterator, data); } +static void +for_each_popup(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data) +{ + struct cg_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); + wlr_xdg_surface_for_each_popup(xdg_shell_view->xdg_surface, iterator, data); +} + static struct wlr_surface * wlr_surface_at(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y) { @@ -297,6 +304,7 @@ static const struct cg_view_impl xdg_shell_view_impl = { .maximize = maximize, .destroy = destroy, .for_each_surface = for_each_surface, + .for_each_popup = for_each_popup, .wlr_surface_at = wlr_surface_at, }; diff --git a/xwayland.c b/xwayland.c index 7d82fb5..180a194 100644 --- a/xwayland.c +++ b/xwayland.c @@ -180,6 +180,8 @@ static const struct cg_view_impl xwayland_view_impl = { .maximize = maximize, .destroy = destroy, .for_each_surface = for_each_surface, + /* XWayland doesn't have a separate popup iterator. */ + .for_each_popup = NULL, .wlr_surface_at = wlr_surface_at, };