aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2018-04-14 15:47:51 -0400
committerGuido Günther <agx@sigxcpu.org>2018-04-23 11:22:23 +0200
commit6b7b64ec1eed0eb2d02c3de69f4352c21ed3c288 (patch)
treeeefe21adc0fb16bbee321509e82fe97cff30b000
parentda944cccb3b118f01a5e8a5406c328ddb75822d7 (diff)
Generalize xdg-shell popups and add to layer-shell
-rw-r--r--include/wlr/types/wlr_layer_shell.h2
-rw-r--r--include/wlr/types/wlr_xdg_shell.h11
-rw-r--r--types/wlr_layer_shell.c18
-rw-r--r--types/wlr_xdg_shell.c66
4 files changed, 57 insertions, 40 deletions
diff --git a/include/wlr/types/wlr_layer_shell.h b/include/wlr/types/wlr_layer_shell.h
index 79b3a4ea..4b3e4e1c 100644
--- a/include/wlr/types/wlr_layer_shell.h
+++ b/include/wlr/types/wlr_layer_shell.h
@@ -59,6 +59,7 @@ struct wlr_layer_surface {
struct wlr_output *output;
struct wl_resource *resource;
struct wlr_layer_shell *shell;
+ struct wl_list popups; // wlr_xdg_popup::link
const char *namespace;
enum zwlr_layer_shell_v1_layer layer;
@@ -81,6 +82,7 @@ struct wlr_layer_surface {
struct wl_signal destroy;
struct wl_signal map;
struct wl_signal unmap;
+ struct wl_signal new_popup;
} events;
void *data;
diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h
index 5046339a..cf96df4a 100644
--- a/include/wlr/types/wlr_xdg_shell.h
+++ b/include/wlr/types/wlr_xdg_shell.h
@@ -32,15 +32,18 @@ struct wlr_xdg_client {
struct wl_event_source *ping_timer;
};
+struct wlr_xdg_positioner;
+
struct wlr_xdg_popup {
struct wlr_xdg_surface *base;
struct wl_list link;
struct wl_resource *resource;
bool committed;
- struct wlr_xdg_surface *parent;
+ struct wlr_surface *parent;
struct wlr_seat *seat;
+ struct wlr_xdg_positioner *positioner;
// Position of the popup relative to the upper left corner of the window
// geometry of the parent surface
struct wlr_box geometry;
@@ -178,6 +181,11 @@ struct wlr_xdg_toplevel_show_window_menu_event {
struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display);
void wlr_xdg_shell_destroy(struct wlr_xdg_shell *xdg_shell);
+struct wlr_xdg_surface *wlr_xdg_surface_from_resource(
+ struct wl_resource *resource);
+
+struct wlr_box wlr_xdg_popup_get_geometry(struct wlr_xdg_popup *popup);
+
/**
* Send a ping to the surface. If the surface does not respond in a reasonable
* amount of time, the ping_timeout event will be emitted.
@@ -226,6 +234,7 @@ void wlr_xdg_surface_send_close(struct wlr_xdg_surface *surface);
/**
* Compute the popup position in its parent's surface-local coordinate system.
+ * This aborts if called for popups whose parent is not an xdg_surface.
*/
void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface,
double *popup_sx, double *popup_sy);
diff --git a/types/wlr_layer_shell.c b/types/wlr_layer_shell.c
index a567b8bc..7e603118 100644
--- a/types/wlr_layer_shell.c
+++ b/types/wlr_layer_shell.c
@@ -6,6 +6,7 @@
#include <wlr/types/wlr_layer_shell.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_surface.h>
+#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#include "util/signal.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
@@ -131,8 +132,19 @@ static void layer_surface_handle_set_keyboard_interactivity(
}
static void layer_surface_handle_get_popup(struct wl_client *client,
- struct wl_resource *resource, struct wl_resource *popup) {
- // TODO
+ struct wl_resource *layer_resource,
+ struct wl_resource *popup_resource) {
+ struct wlr_layer_surface *parent =
+ layer_surface_from_resource(layer_resource);
+ struct wlr_xdg_surface *popup_surface =
+ wlr_xdg_surface_from_resource(popup_resource);
+
+ assert(popup_surface->role == WLR_XDG_SURFACE_ROLE_POPUP);
+ struct wlr_xdg_popup *popup = popup_surface->popup;
+ popup->parent = parent->surface;
+ popup->geometry = wlr_xdg_popup_get_geometry(popup);
+ wl_list_insert(&parent->popups, &popup->link);
+ wlr_signal_emit_safe(&parent->events.new_popup, popup);
}
static const struct zwlr_layer_surface_v1_interface layer_surface_implementation = {
@@ -343,6 +355,7 @@ static void layer_shell_handle_get_layer_surface(struct wl_client *wl_client,
}
wl_list_init(&surface->configure_list);
+ wl_list_init(&surface->popups);
wl_signal_init(&surface->events.destroy);
wl_signal_add(&surface->surface->events.destroy,
@@ -350,6 +363,7 @@ static void layer_shell_handle_get_layer_surface(struct wl_client *wl_client,
surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed;
wl_signal_init(&surface->events.map);
wl_signal_init(&surface->events.unmap);
+ wl_signal_init(&surface->events.new_popup);
wlr_surface_set_role_committed(surface->surface,
handle_wlr_surface_committed, surface);
diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c
index 8d424f3b..080d57a4 100644
--- a/types/wlr_xdg_shell.c
+++ b/types/wlr_xdg_shell.c
@@ -51,16 +51,6 @@ static void resource_handle_destroy(struct wl_client *client,
wl_resource_destroy(resource);
}
-static struct wlr_xdg_surface *xdg_popup_grab_get_topmost(
- struct wlr_xdg_popup_grab *grab) {
- struct wlr_xdg_popup *popup;
- wl_list_for_each(popup, &grab->popups, grab_link) {
- return popup->base;
- }
-
- return NULL;
-}
-
static void xdg_pointer_grab_end(struct wlr_seat_pointer_grab *grab) {
struct wlr_xdg_popup_grab *popup_grab = grab->data;
@@ -447,9 +437,9 @@ static void xdg_shell_handle_create_positioner(struct wl_client *wl_client,
positioner, xdg_positioner_destroy);
}
-static struct wlr_box xdg_positioner_get_geometry(
- struct wlr_xdg_positioner *positioner,
- struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent) {
+struct wlr_box wlr_xdg_popup_get_geometry(struct wlr_xdg_popup *popup) {
+ assert(popup && popup->positioner);
+ struct wlr_xdg_positioner *positioner = popup->positioner;
struct wlr_box geometry = {
.x = positioner->offset.x,
.y = positioner->offset.y,
@@ -563,12 +553,7 @@ static void xdg_popup_handle_grab(struct wl_client *client,
xdg_shell_popup_grab_from_seat(surface->client->shell,
seat_client->seat);
- struct wlr_xdg_surface *topmost = xdg_popup_grab_get_topmost(popup_grab);
- bool parent_is_toplevel =
- surface->popup->parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL;
-
- if ((topmost == NULL && !parent_is_toplevel) ||
- (topmost != NULL && topmost != surface->popup->parent)) {
+ if (!wl_list_empty(&surface->popups)) {
wl_resource_post_error(surface->client->resource,
XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was not created on the topmost popup");
@@ -616,8 +601,12 @@ static void xdg_popup_resource_destroy(struct wl_resource *resource) {
static const struct xdg_surface_interface xdg_surface_implementation;
-static struct wlr_xdg_surface *xdg_surface_from_resource(
+struct wlr_xdg_surface *wlr_xdg_surface_from_resource(
struct wl_resource *resource) {
+ // TODO: Double check that all of the callers can deal with NULL
+ if (!resource) {
+ return NULL;
+ }
assert(wl_resource_instance_of(resource, &xdg_surface_interface,
&xdg_surface_implementation));
return wl_resource_get_user_data(resource);
@@ -628,9 +617,9 @@ static void xdg_surface_handle_get_popup(struct wl_client *client,
struct wl_resource *parent_resource,
struct wl_resource *positioner_resource) {
struct wlr_xdg_surface *surface =
- xdg_surface_from_resource(resource);
+ wlr_xdg_surface_from_resource(resource);
struct wlr_xdg_surface *parent =
- xdg_surface_from_resource(parent_resource);
+ wlr_xdg_surface_from_resource(parent_resource);
struct wlr_xdg_positioner *positioner =
xdg_positioner_from_resource(positioner_resource);
@@ -663,16 +652,18 @@ static void xdg_surface_handle_get_popup(struct wl_client *client,
surface->role = WLR_XDG_SURFACE_ROLE_POPUP;
surface->popup->base = surface;
- surface->popup->parent = parent;
- surface->popup->geometry =
- xdg_positioner_get_geometry(positioner, surface, parent);
- wl_list_insert(&parent->popups, &surface->popup->link);
+ surface->popup->positioner = positioner;
wl_resource_set_implementation(surface->popup->resource,
&xdg_popup_implementation, surface,
xdg_popup_resource_destroy);
- wlr_signal_emit_safe(&parent->events.new_popup, surface->popup);
+ if (parent) {
+ surface->popup->parent = parent->surface;
+ surface->popup->geometry = wlr_xdg_popup_get_geometry(surface->popup);
+ wl_list_insert(&parent->popups, &surface->popup->link);
+ wlr_signal_emit_safe(&parent->events.new_popup, surface->popup);
+ }
}
@@ -913,7 +904,7 @@ static const struct xdg_toplevel_interface xdg_toplevel_implementation = {
static void xdg_surface_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface *surface =
- xdg_surface_from_resource(resource);
+ wlr_xdg_surface_from_resource(resource);
if (surface != NULL) {
xdg_surface_destroy(surface);
}
@@ -929,7 +920,7 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) {
static void xdg_surface_handle_get_toplevel(struct wl_client *client,
struct wl_resource *resource, uint32_t id) {
- struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource);
+ struct wlr_xdg_surface *surface = wlr_xdg_surface_from_resource(resource);
if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role,
resource, XDG_WM_BASE_ERROR_ROLE)) {
@@ -984,7 +975,7 @@ static void wlr_xdg_toplevel_ack_configure(
static void xdg_surface_handle_ack_configure(struct wl_client *client,
struct wl_resource *resource, uint32_t serial) {
- struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource);
+ struct wlr_xdg_surface *surface = wlr_xdg_surface_from_resource(resource);
if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) {
wl_resource_post_error(surface->resource,
@@ -1032,7 +1023,7 @@ static void xdg_surface_handle_ack_configure(struct wl_client *client,
static void xdg_surface_handle_set_window_geometry(struct wl_client *client,
struct wl_resource *resource, int32_t x, int32_t y, int32_t width,
int32_t height) {
- struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource);
+ struct wlr_xdg_surface *surface = wlr_xdg_surface_from_resource(resource);
if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) {
wl_resource_post_error(surface->resource,
@@ -1050,7 +1041,7 @@ static void xdg_surface_handle_set_window_geometry(struct wl_client *client,
static void xdg_surface_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
- struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource);
+ struct wlr_xdg_surface *surface = wlr_xdg_surface_from_resource(resource);
if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) {
wlr_log(L_ERROR, "Tried to destroy an xdg_surface before its role "
@@ -1627,11 +1618,12 @@ void wlr_xdg_surface_send_close(struct wlr_xdg_surface *surface) {
void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface,
double *popup_sx, double *popup_sy) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP);
- struct wlr_xdg_surface *parent = surface->popup->parent;
- *popup_sx = parent->geometry.x + surface->popup->geometry.x -
- surface->geometry.x;
- *popup_sy = parent->geometry.y + surface->popup->geometry.y -
- surface->geometry.y;
+ struct wlr_xdg_popup *popup = surface->popup;
+ assert(strcmp(popup->parent->role, wlr_desktop_xdg_toplevel_role) == 0
+ || strcmp(popup->parent->role, wlr_desktop_xdg_popup_role) == 0);
+ struct wlr_xdg_surface *parent = popup->parent->role_data;
+ *popup_sx = parent->geometry.x + popup->geometry.x - surface->geometry.x;
+ *popup_sy = parent->geometry.y + popup->geometry.y - surface->geometry.y;
}
struct wlr_surface *wlr_xdg_surface_surface_at(