Add wlr_surface_get_geometry

This function defaults and clips the xdg-surface geometry to the
bounding box of the surface + its subsurfaces, as specified by the
protocol spec.
This commit is contained in:
Markus Ongyerth 2018-06-01 13:27:10 +02:00
parent 6b7a55aa3d
commit 3994762ae0
8 changed files with 123 additions and 20 deletions

View file

@ -159,6 +159,14 @@ void wlr_surface_send_leave(struct wlr_surface *surface,
void wlr_surface_send_frame_done(struct wlr_surface *surface, void wlr_surface_send_frame_done(struct wlr_surface *surface,
const struct timespec *when); const struct timespec *when);
struct wlr_box;
/**
* Get the bounding box that contains the surface and all subsurfaces in
* surface coordinates.
* X and y may be negative, if there are subsurfaces with negative position.
*/
void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box);
/** /**
* Set a callback for surface commit that runs before all the other callbacks. * Set a callback for surface commit that runs before all the other callbacks.
* This is intended for use by the surface role. * This is intended for use by the surface role.

View file

@ -341,6 +341,15 @@ bool wlr_surface_is_xdg_surface(struct wlr_surface *surface);
struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface( struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface(
struct wlr_surface *surface); struct wlr_surface *surface);
/**
* Get the surface geometry.
* This is either the geometry as set by the client, or defaulted to the bounds
* of the surface + the subsurfaces (as specified by the protocol).
*
* The x and y value can be <0
*/
void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface, struct wlr_box *box);
/** /**
* Call `iterator` on each surface in the xdg-surface tree, with the surface's * Call `iterator` on each surface in the xdg-surface tree, with the surface's
* position relative to the root xdg-surface. The function is called from root to * position relative to the root xdg-surface. The function is called from root to

View file

@ -318,6 +318,15 @@ bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface);
struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface( struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface(
struct wlr_surface *surface); struct wlr_surface *surface);
/**
* Get the surface geometry.
* This is either the geometry as set by the client, or defaulted to the bounds
* of the surface + the subsurfaces (as specified by the protocol).
*
* The x and y value can be <0
*/
void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box);
/** /**
* Call `iterator` on each surface in the xdg-surface tree, with the surface's * Call `iterator` on each surface in the xdg-surface tree, with the surface's
* position relative to the root xdg-surface. The function is called from root to * position relative to the root xdg-surface. The function is called from root to

View file

@ -132,14 +132,10 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) {
assert(view->type == ROOTS_XDG_SHELL_VIEW); assert(view->type == ROOTS_XDG_SHELL_VIEW);
struct wlr_xdg_surface *surface = view->xdg_surface; struct wlr_xdg_surface *surface = view->xdg_surface;
if (surface->geometry.width > 0 && surface->geometry.height > 0) { struct wlr_box geo_box;
box->width = surface->geometry.width; wlr_xdg_surface_get_geometry(surface, &geo_box);
box->height = surface->geometry.height; box->width = geo_box.width;
} else { box->height = geo_box.height;
assert(surface->surface);
box->width = surface->surface->current->width;
box->height = surface->surface->current->height;
}
} }
static void activate(struct roots_view *view, bool active) { static void activate(struct roots_view *view, bool active) {

View file

@ -133,14 +133,10 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) {
assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); assert(view->type == ROOTS_XDG_SHELL_V6_VIEW);
struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6;
if (surface->geometry.width > 0 && surface->geometry.height > 0) { struct wlr_box geo_box;
box->width = surface->geometry.width; wlr_xdg_surface_v6_get_geometry(surface, &geo_box);
box->height = surface->geometry.height; box->width = geo_box.width;
} else { box->height = geo_box.height;
assert(surface->surface);
box->width = surface->surface->current->width;
box->height = surface->surface->current->height;
}
} }
static void activate(struct roots_view *view, bool active) { static void activate(struct roots_view *view, bool active) {

View file

@ -16,6 +16,22 @@
#define SURFACE_VERSION 4 #define SURFACE_VERSION 4
#define SUBSURFACE_VERSION 1 #define SUBSURFACE_VERSION 1
static int min(int fst, int snd) {
if (fst < snd) {
return fst;
} else {
return snd;
}
}
static int max(int fst, int snd) {
if (fst > snd) {
return fst;
} else {
return snd;
}
}
static void surface_state_reset_buffer(struct wlr_surface_state *state) { static void surface_state_reset_buffer(struct wlr_surface_state *state) {
if (state->buffer) { if (state->buffer) {
wl_list_remove(&state->buffer_destroy_listener.link); wl_list_remove(&state->buffer_destroy_listener.link);
@ -1036,3 +1052,35 @@ void wlr_surface_for_each_surface(struct wlr_surface *surface,
wlr_surface_iterator_func_t iterator, void *user_data) { wlr_surface_iterator_func_t iterator, void *user_data) {
surface_for_each_surface(surface, 0, 0, iterator, user_data); surface_for_each_surface(surface, 0, 0, iterator, user_data);
} }
struct bound_acc {
int32_t min_x, min_y;
int32_t max_x, max_y;
};
static void handle_bounding_box_surface(struct wlr_surface *surface,
int x, int y, void *data) {
struct bound_acc *acc = data;
acc->min_x = min(x, acc->min_x);
acc->min_y = min(x, acc->min_y);
acc->max_x = max(x + surface->current->width, acc->max_x);
acc->max_y = max(y + surface->current->height, acc->max_y);
}
void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box) {
struct bound_acc acc = {
.min_x = 0,
.min_y = 0,
.max_x = surface->current->width,
.max_y = surface->current->height,
};
wlr_surface_for_each_surface(surface, handle_bounding_box_surface, &acc);
box->x = acc.min_x;
box->y = acc.min_y;
box->width = acc.max_x - acc.min_x;
box->height = acc.max_y - acc.min_y;
}

View file

@ -251,6 +251,13 @@ static void xdg_surface_handle_set_window_geometry(struct wl_client *client,
return; return;
} }
if (width <= 0 || height <= 0) {
wlr_log(L_ERROR, "Client tried to set invalid geometry");
//XXX: Switch to the proper error value once available
wl_resource_post_error(resource, -1, "Tried to set invalid xdg-surface geometry");
return;
}
surface->has_next_geometry = true; surface->has_next_geometry = true;
surface->next_geometry.height = height; surface->next_geometry.height = height;
surface->next_geometry.width = width; surface->next_geometry.width = width;
@ -474,9 +481,11 @@ static void xdg_popup_get_position(struct wlr_xdg_popup *popup,
double *popup_sx, double *popup_sy) { double *popup_sx, double *popup_sy) {
struct wlr_xdg_surface *parent = struct wlr_xdg_surface *parent =
wlr_xdg_surface_from_wlr_surface(popup->parent); wlr_xdg_surface_from_wlr_surface(popup->parent);
*popup_sx = parent->geometry.x + popup->geometry.x - struct wlr_box parent_geo;
wlr_xdg_surface_get_geometry(parent, &parent_geo);
*popup_sx = parent_geo.x + popup->geometry.x -
popup->base->geometry.x; popup->base->geometry.x;
*popup_sy = parent->geometry.y + popup->geometry.y - *popup_sy = parent_geo.y + popup->geometry.y -
popup->base->geometry.y; popup->base->geometry.y;
} }
@ -546,3 +555,13 @@ void wlr_xdg_surface_for_each_surface(struct wlr_xdg_surface *surface,
wlr_surface_iterator_func_t iterator, void *user_data) { wlr_surface_iterator_func_t iterator, void *user_data) {
xdg_surface_for_each_surface(surface, 0, 0, iterator, user_data); xdg_surface_for_each_surface(surface, 0, 0, iterator, user_data);
} }
void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface, struct wlr_box *box) {
wlr_surface_get_extends(surface->surface, box);
/* The client never set the geometry */
if (!surface->geometry.width) {
return;
}
wlr_box_intersection(&surface->geometry, box, box);
}

View file

@ -198,6 +198,12 @@ static void xdg_surface_handle_set_window_geometry(struct wl_client *client,
return; return;
} }
if (width <= 0 || height <= 0) {
wlr_log(L_ERROR, "Client tried to set invalid geometry");
wl_resource_post_error(resource, -1, "Tried to set invalid xdg-surface geometry");
}
surface->has_next_geometry = true; surface->has_next_geometry = true;
surface->next_geometry.height = height; surface->next_geometry.height = height;
surface->next_geometry.width = width; surface->next_geometry.width = width;
@ -454,9 +460,11 @@ struct wlr_xdg_surface_v6 *create_xdg_surface_v6(
static void xdg_popup_v6_get_position(struct wlr_xdg_popup_v6 *popup, static void xdg_popup_v6_get_position(struct wlr_xdg_popup_v6 *popup,
double *popup_sx, double *popup_sy) { double *popup_sx, double *popup_sy) {
struct wlr_xdg_surface_v6 *parent = popup->parent; struct wlr_xdg_surface_v6 *parent = popup->parent;
*popup_sx = parent->geometry.x + popup->geometry.x - struct wlr_box parent_geo;
wlr_xdg_surface_v6_get_geometry(parent, &parent_geo);
*popup_sx = parent_geo.x + popup->geometry.x -
popup->base->geometry.x; popup->base->geometry.x;
*popup_sy = parent->geometry.y + popup->geometry.y - *popup_sy = parent_geo.y + popup->geometry.y -
popup->base->geometry.y; popup->base->geometry.y;
} }
@ -526,3 +534,13 @@ void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface,
wlr_surface_iterator_func_t iterator, void *user_data) { wlr_surface_iterator_func_t iterator, void *user_data) {
xdg_surface_v6_for_each_surface(surface, 0, 0, iterator, user_data); xdg_surface_v6_for_each_surface(surface, 0, 0, iterator, user_data);
} }
void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box) {
wlr_surface_get_extends(surface->surface, box);
/* The client never set the geometry */
if (!surface->geometry.width) {
return;
}
wlr_box_intersection(&surface->geometry, box, box);
}