aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_surface.h8
-rw-r--r--include/wlr/types/wlr_xdg_shell.h9
-rw-r--r--include/wlr/types/wlr_xdg_shell_v6.h9
-rw-r--r--rootston/xdg_shell.c12
-rw-r--r--rootston/xdg_shell_v6.c12
-rw-r--r--types/wlr_surface.c48
-rw-r--r--types/xdg_shell/wlr_xdg_surface.c23
-rw-r--r--types/xdg_shell_v6/wlr_xdg_surface_v6.c22
8 files changed, 123 insertions, 20 deletions
diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h
index d1127c86..0fa7e9c2 100644
--- a/include/wlr/types/wlr_surface.h
+++ b/include/wlr/types/wlr_surface.h
@@ -159,6 +159,14 @@ void wlr_surface_send_leave(struct wlr_surface *surface,
void wlr_surface_send_frame_done(struct wlr_surface *surface,
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.
* This is intended for use by the surface role.
diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h
index 5eb30a16..6a967bc7 100644
--- a/include/wlr/types/wlr_xdg_shell.h
+++ b/include/wlr/types/wlr_xdg_shell.h
@@ -342,6 +342,15 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_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
* position relative to the root xdg-surface. The function is called from root to
* leaves (in rendering order).
diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h
index 2fdf49e5..07c831ce 100644
--- a/include/wlr/types/wlr_xdg_shell_v6.h
+++ b/include/wlr/types/wlr_xdg_shell_v6.h
@@ -319,6 +319,15 @@ struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_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
* position relative to the root xdg-surface. The function is called from root to
* leaves (in rendering order).
diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c
index 03ae1dc6..805fb874 100644
--- a/rootston/xdg_shell.c
+++ b/rootston/xdg_shell.c
@@ -132,14 +132,10 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) {
assert(view->type == ROOTS_XDG_SHELL_VIEW);
struct wlr_xdg_surface *surface = view->xdg_surface;
- if (surface->geometry.width > 0 && surface->geometry.height > 0) {
- box->width = surface->geometry.width;
- box->height = surface->geometry.height;
- } else {
- assert(surface->surface);
- box->width = surface->surface->current->width;
- box->height = surface->surface->current->height;
- }
+ struct wlr_box geo_box;
+ wlr_xdg_surface_get_geometry(surface, &geo_box);
+ box->width = geo_box.width;
+ box->height = geo_box.height;
}
static void activate(struct roots_view *view, bool active) {
diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c
index 90b11690..02ad867d 100644
--- a/rootston/xdg_shell_v6.c
+++ b/rootston/xdg_shell_v6.c
@@ -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);
struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6;
- if (surface->geometry.width > 0 && surface->geometry.height > 0) {
- box->width = surface->geometry.width;
- box->height = surface->geometry.height;
- } else {
- assert(surface->surface);
- box->width = surface->surface->current->width;
- box->height = surface->surface->current->height;
- }
+ struct wlr_box geo_box;
+ wlr_xdg_surface_v6_get_geometry(surface, &geo_box);
+ box->width = geo_box.width;
+ box->height = geo_box.height;
}
static void activate(struct roots_view *view, bool active) {
diff --git a/types/wlr_surface.c b/types/wlr_surface.c
index 61284416..6df66f2c 100644
--- a/types/wlr_surface.c
+++ b/types/wlr_surface.c
@@ -16,6 +16,22 @@
#define SURFACE_VERSION 4
#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) {
if (state->buffer) {
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) {
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;
+}
diff --git a/types/xdg_shell/wlr_xdg_surface.c b/types/xdg_shell/wlr_xdg_surface.c
index 6f0e7264..c5d177b2 100644
--- a/types/xdg_shell/wlr_xdg_surface.c
+++ b/types/xdg_shell/wlr_xdg_surface.c
@@ -251,6 +251,13 @@ static void xdg_surface_handle_set_window_geometry(struct wl_client *client,
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->next_geometry.height = height;
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) {
struct wlr_xdg_surface *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_sy = parent->geometry.y + popup->geometry.y -
+ *popup_sy = parent_geo.y + popup->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) {
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);
+}
diff --git a/types/xdg_shell_v6/wlr_xdg_surface_v6.c b/types/xdg_shell_v6/wlr_xdg_surface_v6.c
index a1214a0a..e111adad 100644
--- a/types/xdg_shell_v6/wlr_xdg_surface_v6.c
+++ b/types/xdg_shell_v6/wlr_xdg_surface_v6.c
@@ -198,6 +198,12 @@ static void xdg_surface_handle_set_window_geometry(struct wl_client *client,
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->next_geometry.height = height;
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,
double *popup_sx, double *popup_sy) {
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_sy = parent->geometry.y + popup->geometry.y -
+ *popup_sy = parent_geo.y + popup->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) {
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);
+}