Generalize xdg-shell popups and add to layer-shell

This commit is contained in:
Drew DeVault 2018-04-14 15:47:51 -04:00 committed by Guido Günther
parent da944cccb3
commit 6b7b64ec1e
4 changed files with 57 additions and 40 deletions

View File

@ -59,6 +59,7 @@ struct wlr_layer_surface {
struct wlr_output *output; struct wlr_output *output;
struct wl_resource *resource; struct wl_resource *resource;
struct wlr_layer_shell *shell; struct wlr_layer_shell *shell;
struct wl_list popups; // wlr_xdg_popup::link
const char *namespace; const char *namespace;
enum zwlr_layer_shell_v1_layer layer; enum zwlr_layer_shell_v1_layer layer;
@ -81,6 +82,7 @@ struct wlr_layer_surface {
struct wl_signal destroy; struct wl_signal destroy;
struct wl_signal map; struct wl_signal map;
struct wl_signal unmap; struct wl_signal unmap;
struct wl_signal new_popup;
} events; } events;
void *data; void *data;

View File

@ -32,15 +32,18 @@ struct wlr_xdg_client {
struct wl_event_source *ping_timer; struct wl_event_source *ping_timer;
}; };
struct wlr_xdg_positioner;
struct wlr_xdg_popup { struct wlr_xdg_popup {
struct wlr_xdg_surface *base; struct wlr_xdg_surface *base;
struct wl_list link; struct wl_list link;
struct wl_resource *resource; struct wl_resource *resource;
bool committed; bool committed;
struct wlr_xdg_surface *parent; struct wlr_surface *parent;
struct wlr_seat *seat; struct wlr_seat *seat;
struct wlr_xdg_positioner *positioner;
// Position of the popup relative to the upper left corner of the window // Position of the popup relative to the upper left corner of the window
// geometry of the parent surface // geometry of the parent surface
struct wlr_box geometry; 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); struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display);
void wlr_xdg_shell_destroy(struct wlr_xdg_shell *xdg_shell); 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 * 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. * 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. * 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, void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface,
double *popup_sx, double *popup_sy); double *popup_sx, double *popup_sy);

View File

@ -6,6 +6,7 @@
#include <wlr/types/wlr_layer_shell.h> #include <wlr/types/wlr_layer_shell.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_surface.h> #include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "util/signal.h" #include "util/signal.h"
#include "wlr-layer-shell-unstable-v1-protocol.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, static void layer_surface_handle_get_popup(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *popup) { struct wl_resource *layer_resource,
// TODO 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 = { 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->configure_list);
wl_list_init(&surface->popups);
wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.destroy);
wl_signal_add(&surface->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; surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed;
wl_signal_init(&surface->events.map); wl_signal_init(&surface->events.map);
wl_signal_init(&surface->events.unmap); wl_signal_init(&surface->events.unmap);
wl_signal_init(&surface->events.new_popup);
wlr_surface_set_role_committed(surface->surface, wlr_surface_set_role_committed(surface->surface,
handle_wlr_surface_committed, surface); handle_wlr_surface_committed, surface);

View File

@ -51,16 +51,6 @@ static void resource_handle_destroy(struct wl_client *client,
wl_resource_destroy(resource); 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) { static void xdg_pointer_grab_end(struct wlr_seat_pointer_grab *grab) {
struct wlr_xdg_popup_grab *popup_grab = grab->data; 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); positioner, xdg_positioner_destroy);
} }
static struct wlr_box xdg_positioner_get_geometry( struct wlr_box wlr_xdg_popup_get_geometry(struct wlr_xdg_popup *popup) {
struct wlr_xdg_positioner *positioner, assert(popup && popup->positioner);
struct wlr_xdg_surface *surface, struct wlr_xdg_surface *parent) { struct wlr_xdg_positioner *positioner = popup->positioner;
struct wlr_box geometry = { struct wlr_box geometry = {
.x = positioner->offset.x, .x = positioner->offset.x,
.y = positioner->offset.y, .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, xdg_shell_popup_grab_from_seat(surface->client->shell,
seat_client->seat); seat_client->seat);
struct wlr_xdg_surface *topmost = xdg_popup_grab_get_topmost(popup_grab); if (!wl_list_empty(&surface->popups)) {
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)) {
wl_resource_post_error(surface->client->resource, wl_resource_post_error(surface->client->resource,
XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was not created on 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 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) { 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, assert(wl_resource_instance_of(resource, &xdg_surface_interface,
&xdg_surface_implementation)); &xdg_surface_implementation));
return wl_resource_get_user_data(resource); 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 *parent_resource,
struct wl_resource *positioner_resource) { struct wl_resource *positioner_resource) {
struct wlr_xdg_surface *surface = struct wlr_xdg_surface *surface =
xdg_surface_from_resource(resource); wlr_xdg_surface_from_resource(resource);
struct wlr_xdg_surface *parent = struct wlr_xdg_surface *parent =
xdg_surface_from_resource(parent_resource); wlr_xdg_surface_from_resource(parent_resource);
struct wlr_xdg_positioner *positioner = struct wlr_xdg_positioner *positioner =
xdg_positioner_from_resource(positioner_resource); 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->role = WLR_XDG_SURFACE_ROLE_POPUP;
surface->popup->base = surface; surface->popup->base = surface;
surface->popup->parent = parent; surface->popup->positioner = positioner;
surface->popup->geometry =
xdg_positioner_get_geometry(positioner, surface, parent);
wl_list_insert(&parent->popups, &surface->popup->link);
wl_resource_set_implementation(surface->popup->resource, wl_resource_set_implementation(surface->popup->resource,
&xdg_popup_implementation, surface, &xdg_popup_implementation, surface,
xdg_popup_resource_destroy); 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) { static void xdg_surface_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface *surface = struct wlr_xdg_surface *surface =
xdg_surface_from_resource(resource); wlr_xdg_surface_from_resource(resource);
if (surface != NULL) { if (surface != NULL) {
xdg_surface_destroy(surface); 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, static void xdg_surface_handle_get_toplevel(struct wl_client *client,
struct wl_resource *resource, uint32_t id) { 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, if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role,
resource, XDG_WM_BASE_ERROR_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, static void xdg_surface_handle_ack_configure(struct wl_client *client,
struct wl_resource *resource, uint32_t serial) { 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) { if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) {
wl_resource_post_error(surface->resource, 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, 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, struct wl_resource *resource, int32_t x, int32_t y, int32_t width,
int32_t height) { 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) { if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) {
wl_resource_post_error(surface->resource, 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, static void xdg_surface_handle_destroy(struct wl_client *client,
struct wl_resource *resource) { 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) { if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) {
wlr_log(L_ERROR, "Tried to destroy an xdg_surface before its role " 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, void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface,
double *popup_sx, double *popup_sy) { double *popup_sx, double *popup_sy) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP);
struct wlr_xdg_surface *parent = surface->popup->parent; struct wlr_xdg_popup *popup = surface->popup;
*popup_sx = parent->geometry.x + surface->popup->geometry.x - assert(strcmp(popup->parent->role, wlr_desktop_xdg_toplevel_role) == 0
surface->geometry.x; || strcmp(popup->parent->role, wlr_desktop_xdg_popup_role) == 0);
*popup_sy = parent->geometry.y + surface->popup->geometry.y - struct wlr_xdg_surface *parent = popup->parent->role_data;
surface->geometry.y; *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( struct wlr_surface *wlr_xdg_surface_surface_at(