2018-05-14 23:28:45 +02:00
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "types/wlr_xdg_shell.h"
|
|
|
|
|
2022-03-05 17:32:35 +01:00
|
|
|
void handle_xdg_popup_ack_configure(
|
|
|
|
struct wlr_xdg_popup *popup,
|
|
|
|
struct wlr_xdg_popup_configure *configure) {
|
2022-04-13 19:22:14 +02:00
|
|
|
popup->pending.geometry = configure->geometry;
|
2022-04-12 10:45:21 +02:00
|
|
|
popup->pending.reactive = configure->rules.reactive;
|
2022-03-05 17:32:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct wlr_xdg_popup_configure *send_xdg_popup_configure(
|
|
|
|
struct wlr_xdg_popup *popup) {
|
2023-10-03 07:51:07 +02:00
|
|
|
struct wlr_xdg_popup_configure *configure = calloc(1, sizeof(*configure));
|
2022-03-05 17:32:35 +01:00
|
|
|
if (configure == NULL) {
|
|
|
|
wl_resource_post_no_memory(popup->resource);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
*configure = popup->scheduled;
|
|
|
|
|
2022-06-21 06:42:58 +02:00
|
|
|
uint32_t version = wl_resource_get_version(popup->resource);
|
|
|
|
|
|
|
|
if ((configure->fields & WLR_XDG_POPUP_CONFIGURE_REPOSITION_TOKEN) &&
|
|
|
|
version >= XDG_POPUP_REPOSITIONED_SINCE_VERSION) {
|
2022-04-13 19:40:23 +02:00
|
|
|
xdg_popup_send_repositioned(popup->resource,
|
2022-06-21 06:42:58 +02:00
|
|
|
configure->reposition_token);
|
2022-04-13 19:40:23 +02:00
|
|
|
}
|
|
|
|
|
2022-03-05 17:32:35 +01:00
|
|
|
struct wlr_box *geometry = &configure->geometry;
|
|
|
|
xdg_popup_send_configure(popup->resource,
|
|
|
|
geometry->x, geometry->y,
|
|
|
|
geometry->width, geometry->height);
|
|
|
|
|
2022-06-21 06:42:58 +02:00
|
|
|
popup->scheduled.fields = 0;
|
|
|
|
|
2022-03-05 17:32:35 +01:00
|
|
|
return configure;
|
|
|
|
}
|
|
|
|
|
2019-08-08 03:51:15 +02:00
|
|
|
static void xdg_popup_grab_end(struct wlr_xdg_popup_grab *popup_grab) {
|
2018-05-14 23:28:45 +02:00
|
|
|
struct wlr_xdg_popup *popup, *tmp;
|
|
|
|
wl_list_for_each_safe(popup, tmp, &popup_grab->popups, grab_link) {
|
|
|
|
xdg_popup_send_popup_done(popup->resource);
|
|
|
|
}
|
|
|
|
|
2019-08-08 03:51:15 +02:00
|
|
|
wlr_seat_pointer_end_grab(popup_grab->seat);
|
|
|
|
wlr_seat_keyboard_end_grab(popup_grab->seat);
|
|
|
|
wlr_seat_touch_end_grab(popup_grab->seat);
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab,
|
|
|
|
struct wlr_surface *surface, double sx, double sy) {
|
|
|
|
struct wlr_xdg_popup_grab *popup_grab = grab->data;
|
2019-08-27 04:06:20 +02:00
|
|
|
if (wl_resource_get_client(surface->resource) == popup_grab->client) {
|
2018-05-14 23:28:45 +02:00
|
|
|
wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
|
|
|
|
} else {
|
|
|
|
wlr_seat_pointer_clear_focus(grab->seat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-21 03:04:09 +02:00
|
|
|
static void xdg_pointer_grab_clear_focus(struct wlr_seat_pointer_grab *grab) {
|
|
|
|
wlr_seat_pointer_clear_focus(grab->seat);
|
|
|
|
}
|
|
|
|
|
2018-05-14 23:28:45 +02:00
|
|
|
static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab,
|
|
|
|
uint32_t time, double sx, double sy) {
|
|
|
|
wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab,
|
|
|
|
uint32_t time, uint32_t button, uint32_t state) {
|
|
|
|
uint32_t serial =
|
|
|
|
wlr_seat_pointer_send_button(grab->seat, time, button, state);
|
|
|
|
if (serial) {
|
|
|
|
return serial;
|
|
|
|
} else {
|
2019-08-08 03:51:15 +02:00
|
|
|
xdg_popup_grab_end(grab->data);
|
2018-05-14 23:28:45 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xdg_pointer_grab_axis(struct wlr_seat_pointer_grab *grab,
|
|
|
|
uint32_t time, enum wlr_axis_orientation orientation, double value,
|
|
|
|
int32_t value_discrete, enum wlr_axis_source source) {
|
|
|
|
wlr_seat_pointer_send_axis(grab->seat, time, orientation, value,
|
|
|
|
value_discrete, source);
|
|
|
|
}
|
|
|
|
|
2019-01-30 10:31:53 +01:00
|
|
|
static void xdg_pointer_grab_frame(struct wlr_seat_pointer_grab *grab) {
|
|
|
|
wlr_seat_pointer_send_frame(grab->seat);
|
|
|
|
}
|
|
|
|
|
2018-05-14 23:28:45 +02:00
|
|
|
static void xdg_pointer_grab_cancel(struct wlr_seat_pointer_grab *grab) {
|
2019-08-08 03:51:15 +02:00
|
|
|
xdg_popup_grab_end(grab->data);
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wlr_pointer_grab_interface xdg_pointer_grab_impl = {
|
|
|
|
.enter = xdg_pointer_grab_enter,
|
2020-05-21 03:04:09 +02:00
|
|
|
.clear_focus = xdg_pointer_grab_clear_focus,
|
2018-05-14 23:28:45 +02:00
|
|
|
.motion = xdg_pointer_grab_motion,
|
|
|
|
.button = xdg_pointer_grab_button,
|
|
|
|
.cancel = xdg_pointer_grab_cancel,
|
|
|
|
.axis = xdg_pointer_grab_axis,
|
2019-01-30 10:31:53 +01:00
|
|
|
.frame = xdg_pointer_grab_frame,
|
2018-05-14 23:28:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static void xdg_keyboard_grab_enter(struct wlr_seat_keyboard_grab *grab,
|
2022-12-19 10:12:25 +01:00
|
|
|
struct wlr_surface *surface, const uint32_t keycodes[], size_t num_keycodes,
|
|
|
|
const struct wlr_keyboard_modifiers *modifiers) {
|
2018-05-14 23:28:45 +02:00
|
|
|
// keyboard focus should remain on the popup
|
|
|
|
}
|
|
|
|
|
2020-05-21 03:04:09 +02:00
|
|
|
static void xdg_keyboard_grab_clear_focus(struct wlr_seat_keyboard_grab *grab) {
|
|
|
|
// keyboard focus should remain on the popup
|
|
|
|
}
|
|
|
|
|
2018-05-14 23:28:45 +02:00
|
|
|
static void xdg_keyboard_grab_key(struct wlr_seat_keyboard_grab *grab, uint32_t time,
|
|
|
|
uint32_t key, uint32_t state) {
|
|
|
|
wlr_seat_keyboard_send_key(grab->seat, time, key, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xdg_keyboard_grab_modifiers(struct wlr_seat_keyboard_grab *grab,
|
2022-12-19 10:10:38 +01:00
|
|
|
const struct wlr_keyboard_modifiers *modifiers) {
|
2018-05-14 23:28:45 +02:00
|
|
|
wlr_seat_keyboard_send_modifiers(grab->seat, modifiers);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xdg_keyboard_grab_cancel(struct wlr_seat_keyboard_grab *grab) {
|
2018-06-25 00:48:13 +02:00
|
|
|
wlr_seat_pointer_end_grab(grab->seat);
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = {
|
|
|
|
.enter = xdg_keyboard_grab_enter,
|
2020-05-21 03:04:09 +02:00
|
|
|
.clear_focus = xdg_keyboard_grab_clear_focus,
|
2018-05-14 23:28:45 +02:00
|
|
|
.key = xdg_keyboard_grab_key,
|
|
|
|
.modifiers = xdg_keyboard_grab_modifiers,
|
|
|
|
.cancel = xdg_keyboard_grab_cancel,
|
|
|
|
};
|
|
|
|
|
2019-08-08 03:51:15 +02:00
|
|
|
static uint32_t xdg_touch_grab_down(struct wlr_seat_touch_grab *grab,
|
|
|
|
uint32_t time, struct wlr_touch_point *point) {
|
|
|
|
struct wlr_xdg_popup_grab *popup_grab = grab->data;
|
|
|
|
|
2019-08-27 04:06:20 +02:00
|
|
|
if (wl_resource_get_client(point->surface->resource) != popup_grab->client) {
|
2019-08-08 03:51:15 +02:00
|
|
|
xdg_popup_grab_end(grab->data);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return wlr_seat_touch_send_down(grab->seat, point->surface, time,
|
|
|
|
point->touch_id, point->sx, point->sy);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xdg_touch_grab_up(struct wlr_seat_touch_grab *grab,
|
|
|
|
uint32_t time, struct wlr_touch_point *point) {
|
|
|
|
wlr_seat_touch_send_up(grab->seat, time, point->touch_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xdg_touch_grab_motion(struct wlr_seat_touch_grab *grab,
|
|
|
|
uint32_t time, struct wlr_touch_point *point) {
|
|
|
|
wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx,
|
|
|
|
point->sy);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xdg_touch_grab_enter(struct wlr_seat_touch_grab *grab,
|
|
|
|
uint32_t time, struct wlr_touch_point *point) {
|
|
|
|
}
|
|
|
|
|
2021-06-30 13:09:45 +02:00
|
|
|
static void xdg_touch_grab_frame(struct wlr_seat_touch_grab *grab) {
|
|
|
|
wlr_seat_touch_send_frame(grab->seat);
|
|
|
|
}
|
|
|
|
|
2019-08-08 03:51:15 +02:00
|
|
|
static void xdg_touch_grab_cancel(struct wlr_seat_touch_grab *grab) {
|
|
|
|
wlr_seat_touch_end_grab(grab->seat);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wlr_touch_grab_interface xdg_touch_grab_impl = {
|
|
|
|
.down = xdg_touch_grab_down,
|
|
|
|
.up = xdg_touch_grab_up,
|
|
|
|
.motion = xdg_touch_grab_motion,
|
|
|
|
.enter = xdg_touch_grab_enter,
|
2021-06-30 13:09:45 +02:00
|
|
|
.frame = xdg_touch_grab_frame,
|
2019-08-08 03:51:15 +02:00
|
|
|
.cancel = xdg_touch_grab_cancel
|
|
|
|
};
|
|
|
|
|
2022-01-08 20:52:56 +01:00
|
|
|
static void destroy_xdg_popup_grab(struct wlr_xdg_popup_grab *xdg_grab) {
|
|
|
|
if (xdg_grab == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2018-05-14 23:28:45 +02:00
|
|
|
|
|
|
|
wl_list_remove(&xdg_grab->seat_destroy.link);
|
|
|
|
|
2022-01-08 20:52:56 +01:00
|
|
|
struct wlr_xdg_popup *popup, *tmp;
|
|
|
|
wl_list_for_each_safe(popup, tmp, &xdg_grab->popups, grab_link) {
|
2023-07-26 10:02:09 +02:00
|
|
|
wlr_xdg_popup_destroy(popup);
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
wl_list_remove(&xdg_grab->link);
|
|
|
|
free(xdg_grab);
|
|
|
|
}
|
|
|
|
|
2022-01-08 20:52:56 +01:00
|
|
|
static void xdg_popup_grab_handle_seat_destroy(
|
|
|
|
struct wl_listener *listener, void *data) {
|
|
|
|
struct wlr_xdg_popup_grab *xdg_grab =
|
|
|
|
wl_container_of(listener, xdg_grab, seat_destroy);
|
|
|
|
destroy_xdg_popup_grab(xdg_grab);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct wlr_xdg_popup_grab *get_xdg_shell_popup_grab_from_seat(
|
2018-05-14 23:28:45 +02:00
|
|
|
struct wlr_xdg_shell *shell, struct wlr_seat *seat) {
|
|
|
|
struct wlr_xdg_popup_grab *xdg_grab;
|
|
|
|
wl_list_for_each(xdg_grab, &shell->popup_grabs, link) {
|
|
|
|
if (xdg_grab->seat == seat) {
|
|
|
|
return xdg_grab;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-03 07:51:07 +02:00
|
|
|
xdg_grab = calloc(1, sizeof(*xdg_grab));
|
2018-05-14 23:28:45 +02:00
|
|
|
if (!xdg_grab) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
xdg_grab->pointer_grab.data = xdg_grab;
|
|
|
|
xdg_grab->pointer_grab.interface = &xdg_pointer_grab_impl;
|
|
|
|
xdg_grab->keyboard_grab.data = xdg_grab;
|
|
|
|
xdg_grab->keyboard_grab.interface = &xdg_keyboard_grab_impl;
|
2019-08-08 03:51:15 +02:00
|
|
|
xdg_grab->touch_grab.data = xdg_grab;
|
|
|
|
xdg_grab->touch_grab.interface = &xdg_touch_grab_impl;
|
2018-05-14 23:28:45 +02:00
|
|
|
|
|
|
|
wl_list_init(&xdg_grab->popups);
|
|
|
|
|
|
|
|
wl_list_insert(&shell->popup_grabs, &xdg_grab->link);
|
|
|
|
xdg_grab->seat = seat;
|
|
|
|
|
|
|
|
xdg_grab->seat_destroy.notify = xdg_popup_grab_handle_seat_destroy;
|
|
|
|
wl_signal_add(&seat->events.destroy, &xdg_grab->seat_destroy);
|
|
|
|
|
|
|
|
return xdg_grab;
|
|
|
|
}
|
|
|
|
|
2022-01-08 20:52:52 +01:00
|
|
|
void handle_xdg_popup_committed(struct wlr_xdg_popup *popup) {
|
|
|
|
if (!popup->parent) {
|
|
|
|
wl_resource_post_error(popup->base->resource,
|
2021-09-11 11:55:15 +02:00
|
|
|
XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
|
|
|
|
"xdg_popup has no parent");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-26 18:25:34 +02:00
|
|
|
popup->current = popup->pending;
|
|
|
|
|
|
|
|
if (popup->base->initial_commit && !popup->sent_initial_configure) {
|
2022-01-08 20:52:52 +01:00
|
|
|
wlr_xdg_surface_schedule_configure(popup->base);
|
2023-01-31 16:16:54 +01:00
|
|
|
popup->sent_initial_configure = true;
|
2021-09-11 11:55:15 +02:00
|
|
|
}
|
|
|
|
}
|
2018-05-14 23:28:45 +02:00
|
|
|
|
|
|
|
static const struct xdg_popup_interface xdg_popup_implementation;
|
|
|
|
|
2022-01-08 20:52:52 +01:00
|
|
|
struct wlr_xdg_popup *wlr_xdg_popup_from_resource(
|
2018-05-14 23:28:45 +02:00
|
|
|
struct wl_resource *resource) {
|
|
|
|
assert(wl_resource_instance_of(resource, &xdg_popup_interface,
|
|
|
|
&xdg_popup_implementation));
|
|
|
|
return wl_resource_get_user_data(resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xdg_popup_handle_grab(struct wl_client *client,
|
|
|
|
struct wl_resource *resource, struct wl_resource *seat_resource,
|
|
|
|
uint32_t serial) {
|
2022-01-08 20:52:52 +01:00
|
|
|
struct wlr_xdg_popup *popup =
|
|
|
|
wlr_xdg_popup_from_resource(resource);
|
|
|
|
if (!popup) {
|
2018-06-28 13:14:37 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-05-14 23:28:45 +02:00
|
|
|
|
2022-01-08 20:52:52 +01:00
|
|
|
struct wlr_seat_client *seat_client =
|
|
|
|
wlr_seat_client_from_resource(seat_resource);
|
2023-06-01 13:10:09 +02:00
|
|
|
if (seat_client == NULL) {
|
2023-07-26 10:02:09 +02:00
|
|
|
wlr_xdg_popup_destroy(popup);
|
2023-06-01 13:10:09 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-01-31 16:16:54 +01:00
|
|
|
if (popup->sent_initial_configure) {
|
2022-01-08 20:52:52 +01:00
|
|
|
wl_resource_post_error(popup->resource,
|
2018-05-14 23:28:45 +02:00
|
|
|
XDG_POPUP_ERROR_INVALID_GRAB,
|
|
|
|
"xdg_popup is already mapped");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct wlr_xdg_popup_grab *popup_grab = get_xdg_shell_popup_grab_from_seat(
|
2022-01-08 20:52:52 +01:00
|
|
|
popup->base->client->shell, seat_client->seat);
|
2018-05-14 23:28:45 +02:00
|
|
|
|
2022-01-08 20:52:52 +01:00
|
|
|
if (!wl_list_empty(&popup->base->popups)) {
|
|
|
|
wl_resource_post_error(popup->base->client->resource,
|
2018-05-14 23:28:45 +02:00
|
|
|
XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
|
|
|
|
"xdg_popup was not created on the topmost popup");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-08 20:52:52 +01:00
|
|
|
popup_grab->client = popup->base->client->client;
|
|
|
|
popup->seat = seat_client->seat;
|
2018-05-14 23:28:45 +02:00
|
|
|
|
2022-01-08 20:52:52 +01:00
|
|
|
wl_list_insert(&popup_grab->popups, &popup->grab_link);
|
2018-05-14 23:28:45 +02:00
|
|
|
|
|
|
|
wlr_seat_pointer_start_grab(seat_client->seat,
|
|
|
|
&popup_grab->pointer_grab);
|
|
|
|
wlr_seat_keyboard_start_grab(seat_client->seat,
|
|
|
|
&popup_grab->keyboard_grab);
|
2019-08-08 03:51:15 +02:00
|
|
|
wlr_seat_touch_start_grab(seat_client->seat,
|
|
|
|
&popup_grab->touch_grab);
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
|
|
|
|
2022-04-13 19:40:23 +02:00
|
|
|
static void xdg_popup_handle_reposition(
|
|
|
|
struct wl_client *client, struct wl_resource *resource,
|
|
|
|
struct wl_resource *positioner_resource, uint32_t token) {
|
|
|
|
struct wlr_xdg_popup *popup =
|
|
|
|
wlr_xdg_popup_from_resource(resource);
|
|
|
|
if (!popup) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct wlr_xdg_positioner *positioner =
|
|
|
|
wlr_xdg_positioner_from_resource(positioner_resource);
|
|
|
|
wlr_xdg_positioner_rules_get_geometry(
|
|
|
|
&positioner->rules, &popup->scheduled.geometry);
|
|
|
|
popup->scheduled.rules = positioner->rules;
|
2022-06-21 06:42:58 +02:00
|
|
|
|
|
|
|
popup->scheduled.fields |= WLR_XDG_POPUP_CONFIGURE_REPOSITION_TOKEN;
|
2022-04-13 19:40:23 +02:00
|
|
|
popup->scheduled.reposition_token = token;
|
|
|
|
|
|
|
|
wlr_xdg_surface_schedule_configure(popup->base);
|
|
|
|
|
2022-08-18 13:16:16 +02:00
|
|
|
wl_signal_emit_mutable(&popup->events.reposition, NULL);
|
2022-04-13 19:40:23 +02:00
|
|
|
}
|
|
|
|
|
2018-05-14 23:28:45 +02:00
|
|
|
static void xdg_popup_handle_destroy(struct wl_client *client,
|
|
|
|
struct wl_resource *resource) {
|
2022-01-08 20:52:52 +01:00
|
|
|
struct wlr_xdg_popup *popup =
|
|
|
|
wlr_xdg_popup_from_resource(resource);
|
2018-05-14 23:28:45 +02:00
|
|
|
|
2022-01-08 20:52:52 +01:00
|
|
|
if (popup && !wl_list_empty(&popup->base->popups)) {
|
|
|
|
wl_resource_post_error(popup->base->client->resource,
|
2018-05-14 23:28:45 +02:00
|
|
|
XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP,
|
|
|
|
"xdg_popup was destroyed while it was not the topmost popup");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_resource_destroy(resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct xdg_popup_interface xdg_popup_implementation = {
|
|
|
|
.destroy = xdg_popup_handle_destroy,
|
|
|
|
.grab = xdg_popup_handle_grab,
|
2022-04-13 19:40:23 +02:00
|
|
|
.reposition = xdg_popup_handle_reposition,
|
2018-05-14 23:28:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static void xdg_popup_handle_resource_destroy(struct wl_resource *resource) {
|
2022-01-08 20:52:52 +01:00
|
|
|
struct wlr_xdg_popup *popup =
|
|
|
|
wlr_xdg_popup_from_resource(resource);
|
|
|
|
if (popup == NULL) {
|
2019-02-05 19:27:23 +01:00
|
|
|
return;
|
|
|
|
}
|
2022-01-08 20:52:52 +01:00
|
|
|
wlr_xdg_popup_destroy(popup);
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
|
|
|
|
2022-01-08 20:52:53 +01:00
|
|
|
void create_xdg_popup(struct wlr_xdg_surface *surface,
|
2018-05-14 23:28:45 +02:00
|
|
|
struct wlr_xdg_surface *parent,
|
2022-02-06 21:39:50 +01:00
|
|
|
struct wlr_xdg_positioner *positioner, uint32_t id) {
|
|
|
|
if (positioner->rules.size.width == 0 ||
|
|
|
|
positioner->rules.anchor_rect.width == 0) {
|
2022-02-02 18:54:29 +01:00
|
|
|
wl_resource_post_error(surface->client->resource,
|
2018-05-14 23:28:45 +02:00
|
|
|
XDG_WM_BASE_ERROR_INVALID_POSITIONER,
|
|
|
|
"positioner object is not complete");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-26 10:36:24 +02:00
|
|
|
if (!set_xdg_surface_role(surface, WLR_XDG_SURFACE_ROLE_POPUP)) {
|
2020-07-03 23:25:18 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-01 11:48:22 +02:00
|
|
|
if (parent != NULL && parent->role == WLR_XDG_SURFACE_ROLE_NONE) {
|
|
|
|
wl_resource_post_error(surface->client->resource, XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT,
|
|
|
|
"a popup parent must have a role");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-08 20:52:53 +01:00
|
|
|
assert(surface->popup == NULL);
|
2023-10-03 07:51:07 +02:00
|
|
|
surface->popup = calloc(1, sizeof(*surface->popup));
|
2022-01-08 20:52:53 +01:00
|
|
|
if (!surface->popup) {
|
|
|
|
wl_resource_post_no_memory(surface->resource);
|
2018-12-04 13:42:29 +01:00
|
|
|
return;
|
2018-11-12 19:37:22 +01:00
|
|
|
}
|
2022-01-08 20:52:53 +01:00
|
|
|
surface->popup->base = surface;
|
|
|
|
|
|
|
|
surface->popup->resource = wl_resource_create(
|
|
|
|
surface->client->client, &xdg_popup_interface,
|
|
|
|
wl_resource_get_version(surface->resource), id);
|
|
|
|
if (surface->popup->resource == NULL) {
|
|
|
|
free(surface->popup);
|
2022-01-08 20:52:55 +01:00
|
|
|
surface->popup = NULL;
|
2022-01-08 20:52:53 +01:00
|
|
|
wl_resource_post_no_memory(surface->resource);
|
2018-05-14 23:28:45 +02:00
|
|
|
return;
|
|
|
|
}
|
2022-01-08 20:52:53 +01:00
|
|
|
wl_resource_set_implementation(surface->popup->resource,
|
|
|
|
&xdg_popup_implementation, surface->popup,
|
2018-05-14 23:28:45 +02:00
|
|
|
xdg_popup_handle_resource_destroy);
|
|
|
|
|
2022-01-08 20:52:53 +01:00
|
|
|
surface->role = WLR_XDG_SURFACE_ROLE_POPUP;
|
2018-05-14 23:28:45 +02:00
|
|
|
|
2022-02-06 21:39:50 +01:00
|
|
|
wlr_xdg_positioner_rules_get_geometry(
|
2022-03-05 17:32:35 +01:00
|
|
|
&positioner->rules, &surface->popup->scheduled.geometry);
|
|
|
|
surface->popup->scheduled.rules = positioner->rules;
|
2018-05-14 23:28:45 +02:00
|
|
|
|
2022-04-13 19:40:23 +02:00
|
|
|
wl_signal_init(&surface->popup->events.reposition);
|
|
|
|
|
2018-05-14 23:28:45 +02:00
|
|
|
if (parent) {
|
2022-01-08 20:52:53 +01:00
|
|
|
surface->popup->parent = parent->surface;
|
|
|
|
wl_list_insert(&parent->popups, &surface->popup->link);
|
2022-08-18 13:16:16 +02:00
|
|
|
wl_signal_emit_mutable(&parent->events.new_popup, surface->popup);
|
2018-11-12 19:37:22 +01:00
|
|
|
} else {
|
2022-01-08 20:52:53 +01:00
|
|
|
wl_list_init(&surface->popup->link);
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
2023-07-26 10:36:24 +02:00
|
|
|
|
|
|
|
set_xdg_surface_role_object(surface, surface->popup->resource);
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
|
|
|
|
2023-03-07 18:32:43 +01:00
|
|
|
void reset_xdg_popup(struct wlr_xdg_popup *popup) {
|
2022-01-08 20:52:55 +01:00
|
|
|
if (popup->seat != NULL) {
|
|
|
|
struct wlr_xdg_popup_grab *grab =
|
|
|
|
get_xdg_shell_popup_grab_from_seat(
|
|
|
|
popup->base->client->shell, popup->seat);
|
|
|
|
|
|
|
|
wl_list_remove(&popup->grab_link);
|
|
|
|
|
|
|
|
if (wl_list_empty(&grab->popups)) {
|
|
|
|
if (grab->seat->pointer_state.grab == &grab->pointer_grab) {
|
|
|
|
wlr_seat_pointer_end_grab(grab->seat);
|
|
|
|
}
|
|
|
|
if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) {
|
|
|
|
wlr_seat_keyboard_end_grab(grab->seat);
|
|
|
|
}
|
2022-01-08 20:52:56 +01:00
|
|
|
if (grab->seat->touch_state.grab == &grab->touch_grab) {
|
|
|
|
wlr_seat_touch_end_grab(grab->seat);
|
|
|
|
}
|
2022-04-13 19:40:23 +02:00
|
|
|
|
2022-01-08 20:52:56 +01:00
|
|
|
destroy_xdg_popup_grab(grab);
|
2022-01-08 20:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
popup->seat = NULL;
|
|
|
|
}
|
2023-01-31 15:47:20 +01:00
|
|
|
|
2023-01-31 16:16:54 +01:00
|
|
|
popup->sent_initial_configure = false;
|
2022-01-08 20:52:55 +01:00
|
|
|
}
|
|
|
|
|
2022-02-05 08:29:42 +01:00
|
|
|
void destroy_xdg_popup(struct wlr_xdg_popup *popup) {
|
2023-07-26 10:36:24 +02:00
|
|
|
wlr_surface_unmap(popup->base->surface);
|
|
|
|
reset_xdg_popup(popup);
|
|
|
|
|
|
|
|
// TODO: improve events
|
|
|
|
if (popup->base->added) {
|
|
|
|
wl_signal_emit_mutable(&popup->base->events.destroy, NULL);
|
|
|
|
popup->base->added = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
popup->base->popup = NULL;
|
|
|
|
|
2022-02-05 08:29:42 +01:00
|
|
|
wl_list_remove(&popup->link);
|
|
|
|
wl_resource_set_user_data(popup->resource, NULL);
|
|
|
|
free(popup);
|
|
|
|
}
|
|
|
|
|
2022-01-08 20:52:52 +01:00
|
|
|
void wlr_xdg_popup_destroy(struct wlr_xdg_popup *popup) {
|
|
|
|
if (popup == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct wlr_xdg_popup *child, *child_tmp;
|
|
|
|
wl_list_for_each_safe(child, child_tmp, &popup->base->popups, link) {
|
|
|
|
wlr_xdg_popup_destroy(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
xdg_popup_send_popup_done(popup->resource);
|
2023-07-26 10:36:24 +02:00
|
|
|
destroy_xdg_popup(popup);
|
2022-01-08 20:52:52 +01:00
|
|
|
}
|
|
|
|
|
2018-05-14 23:28:45 +02:00
|
|
|
void wlr_xdg_popup_get_toplevel_coords(struct wlr_xdg_popup *popup,
|
|
|
|
int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy) {
|
2018-12-12 08:51:13 +01:00
|
|
|
struct wlr_surface *parent = popup->parent;
|
2023-02-01 20:12:49 +01:00
|
|
|
struct wlr_xdg_surface *xdg_surface;
|
|
|
|
while ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(parent))) {
|
2023-07-26 09:50:09 +02:00
|
|
|
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && xdg_surface->popup != NULL) {
|
2022-04-13 19:22:14 +02:00
|
|
|
popup_sx += xdg_surface->popup->current.geometry.x;
|
|
|
|
popup_sy += xdg_surface->popup->current.geometry.y;
|
2018-12-12 08:51:13 +01:00
|
|
|
parent = xdg_surface->popup->parent;
|
|
|
|
} else {
|
2021-09-30 20:58:36 +02:00
|
|
|
popup_sx += xdg_surface->current.geometry.x;
|
|
|
|
popup_sy += xdg_surface->current.geometry.y;
|
2018-12-12 08:51:13 +01:00
|
|
|
break;
|
|
|
|
}
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
|
|
|
assert(parent);
|
|
|
|
|
2018-12-12 08:51:13 +01:00
|
|
|
*toplevel_sx = popup_sx;
|
|
|
|
*toplevel_sy = popup_sy;
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void wlr_xdg_popup_unconstrain_from_box(struct wlr_xdg_popup *popup,
|
2022-02-07 12:22:48 +01:00
|
|
|
const struct wlr_box *toplevel_space_box) {
|
|
|
|
int toplevel_sx, toplevel_sy;
|
|
|
|
wlr_xdg_popup_get_toplevel_coords(popup,
|
|
|
|
0, 0, &toplevel_sx, &toplevel_sy);
|
|
|
|
struct wlr_box popup_constraint = {
|
|
|
|
.x = toplevel_space_box->x - toplevel_sx,
|
|
|
|
.y = toplevel_space_box->y - toplevel_sy,
|
|
|
|
.width = toplevel_space_box->width,
|
|
|
|
.height = toplevel_space_box->height,
|
|
|
|
};
|
2022-03-05 17:32:35 +01:00
|
|
|
wlr_xdg_positioner_rules_unconstrain_box(&popup->scheduled.rules,
|
|
|
|
&popup_constraint, &popup->scheduled.geometry);
|
|
|
|
wlr_xdg_surface_schedule_configure(popup->base);
|
2018-05-14 23:28:45 +02:00
|
|
|
}
|