Generalize xdg-shell popups and add to layer-shell
This commit is contained in:
parent
da944cccb3
commit
6b7b64ec1e
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue