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
This commit is contained in:
Johan Malm 2022-02-11 23:12:45 +00:00
parent d2552232c7
commit 532656ad5b
16 changed files with 189 additions and 1465 deletions

View 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);
/*

View file

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

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

View 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;
*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 *

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

View 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',

View file

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

File diff suppressed because it is too large Load diff

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

View file

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

View file

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

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

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

View file

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

View 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

View 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,