mirror of
https://github.com/swaywm/sway.git
synced 2024-12-28 07:56:31 +01:00
layer-shell: add support for popups
This commit is contained in:
parent
f36240208c
commit
cb8f68d74b
4 changed files with 182 additions and 9 deletions
|
@ -5,6 +5,11 @@
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_surface.h>
|
||||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||||
|
|
||||||
|
enum layer_parent {
|
||||||
|
LAYER_PARENT_LAYER,
|
||||||
|
LAYER_PARENT_POPUP,
|
||||||
|
};
|
||||||
|
|
||||||
struct sway_layer_surface {
|
struct sway_layer_surface {
|
||||||
struct wlr_layer_surface_v1 *layer_surface;
|
struct wlr_layer_surface_v1 *layer_surface;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
@ -14,11 +19,26 @@ struct sway_layer_surface {
|
||||||
struct wl_listener unmap;
|
struct wl_listener unmap;
|
||||||
struct wl_listener surface_commit;
|
struct wl_listener surface_commit;
|
||||||
struct wl_listener output_destroy;
|
struct wl_listener output_destroy;
|
||||||
|
struct wl_listener new_popup;
|
||||||
|
|
||||||
bool configured;
|
bool configured;
|
||||||
struct wlr_box geo;
|
struct wlr_box geo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sway_layer_popup {
|
||||||
|
struct wlr_xdg_popup *wlr_popup;
|
||||||
|
enum layer_parent parent_type;
|
||||||
|
union {
|
||||||
|
struct sway_layer_surface *parent_layer;
|
||||||
|
struct sway_layer_popup *parent_popup;
|
||||||
|
};
|
||||||
|
struct wl_listener map;
|
||||||
|
struct wl_listener unmap;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
struct wl_listener commit;
|
||||||
|
struct wl_listener new_popup;
|
||||||
|
};
|
||||||
|
|
||||||
struct sway_output;
|
struct sway_output;
|
||||||
void arrange_layers(struct sway_output *output);
|
void arrange_layers(struct sway_output *output);
|
||||||
|
|
||||||
|
|
|
@ -320,6 +320,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
wl_list_remove(&sway_layer->map.link);
|
wl_list_remove(&sway_layer->map.link);
|
||||||
wl_list_remove(&sway_layer->unmap.link);
|
wl_list_remove(&sway_layer->unmap.link);
|
||||||
wl_list_remove(&sway_layer->surface_commit.link);
|
wl_list_remove(&sway_layer->surface_commit.link);
|
||||||
|
wl_list_remove(&sway_layer->new_popup.link);
|
||||||
if (sway_layer->layer_surface->output != NULL) {
|
if (sway_layer->layer_surface->output != NULL) {
|
||||||
struct sway_output *output = sway_layer->layer_surface->output->data;
|
struct sway_output *output = sway_layer->layer_surface->output->data;
|
||||||
if (output != NULL) {
|
if (output != NULL) {
|
||||||
|
@ -338,7 +339,6 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
||||||
struct sway_output *output = sway_layer->layer_surface->output->data;
|
struct sway_output *output = sway_layer->layer_surface->output->data;
|
||||||
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
|
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
|
||||||
sway_layer->layer_surface->surface, true);
|
sway_layer->layer_surface->surface, true);
|
||||||
// TODO: send enter to subsurfaces and popups
|
|
||||||
wlr_surface_send_enter(sway_layer->layer_surface->surface,
|
wlr_surface_send_enter(sway_layer->layer_surface->surface,
|
||||||
sway_layer->layer_surface->output);
|
sway_layer->layer_surface->output);
|
||||||
cursor_rebase_all();
|
cursor_rebase_all();
|
||||||
|
@ -350,6 +350,131 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
|
||||||
unmap(sway_layer);
|
unmap(sway_layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct sway_layer_surface *popup_get_layer(
|
||||||
|
struct sway_layer_popup *popup) {
|
||||||
|
while (popup->parent_type == LAYER_PARENT_POPUP) {
|
||||||
|
popup = popup->parent_popup;
|
||||||
|
}
|
||||||
|
return popup->parent_layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
|
||||||
|
struct wlr_xdg_popup *popup = layer_popup->wlr_popup;
|
||||||
|
struct wlr_surface *surface = popup->base->surface;
|
||||||
|
int popup_sx = popup->geometry.x - popup->base->geometry.x;
|
||||||
|
int popup_sy = popup->geometry.y - popup->base->geometry.y;
|
||||||
|
int ox = popup_sx, oy = popup_sy;
|
||||||
|
struct sway_layer_surface *layer;
|
||||||
|
while (true) {
|
||||||
|
if (layer_popup->parent_type == LAYER_PARENT_POPUP) {
|
||||||
|
layer_popup = layer_popup->parent_popup;
|
||||||
|
ox += layer_popup->wlr_popup->base->geometry.x +
|
||||||
|
layer_popup->wlr_popup->geometry.x;
|
||||||
|
oy += layer_popup->wlr_popup->base->geometry.y +
|
||||||
|
layer_popup->wlr_popup->geometry.y;
|
||||||
|
} else {
|
||||||
|
layer = layer_popup->parent_layer;
|
||||||
|
ox += layer->geo.x;
|
||||||
|
oy += layer->geo.y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||||
|
struct sway_output *output = wlr_output->data;
|
||||||
|
output_damage_surface(output, ox, oy, surface, whole);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_handle_map(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
|
||||||
|
struct sway_layer_surface *layer = popup_get_layer(popup);
|
||||||
|
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||||
|
wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output);
|
||||||
|
popup_damage(popup, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_handle_unmap(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap);
|
||||||
|
popup_damage(popup, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_handle_commit(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_layer_popup *popup = wl_container_of(listener, popup, commit);
|
||||||
|
popup_damage(popup, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_layer_popup *popup =
|
||||||
|
wl_container_of(listener, popup, destroy);
|
||||||
|
|
||||||
|
wl_list_remove(&popup->map.link);
|
||||||
|
wl_list_remove(&popup->unmap.link);
|
||||||
|
wl_list_remove(&popup->destroy.link);
|
||||||
|
wl_list_remove(&popup->commit.link);
|
||||||
|
free(popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_unconstrain(struct sway_layer_popup *popup) {
|
||||||
|
struct sway_layer_surface *layer = popup_get_layer(popup);
|
||||||
|
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
|
||||||
|
|
||||||
|
struct sway_output *output = layer->layer_surface->output->data;
|
||||||
|
|
||||||
|
// the output box expressed in the coordinate system of the toplevel parent
|
||||||
|
// of the popup
|
||||||
|
struct wlr_box output_toplevel_sx_box = {
|
||||||
|
.x = -layer->geo.x,
|
||||||
|
.y = -layer->geo.y,
|
||||||
|
.width = output->width,
|
||||||
|
.height = output->height,
|
||||||
|
};
|
||||||
|
|
||||||
|
wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
|
||||||
|
|
||||||
|
static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup,
|
||||||
|
enum layer_parent parent_type, void *parent) {
|
||||||
|
struct sway_layer_popup *popup =
|
||||||
|
calloc(1, sizeof(struct sway_layer_popup));
|
||||||
|
if (popup == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
popup->wlr_popup = wlr_popup;
|
||||||
|
popup->parent_type = parent_type;
|
||||||
|
popup->parent_layer = parent;
|
||||||
|
|
||||||
|
popup->map.notify = popup_handle_map;
|
||||||
|
wl_signal_add(&wlr_popup->base->events.map, &popup->map);
|
||||||
|
popup->unmap.notify = popup_handle_unmap;
|
||||||
|
wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap);
|
||||||
|
popup->destroy.notify = popup_handle_destroy;
|
||||||
|
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
|
||||||
|
popup->commit.notify = popup_handle_commit;
|
||||||
|
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
|
||||||
|
popup->new_popup.notify = popup_handle_new_popup;
|
||||||
|
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
|
||||||
|
|
||||||
|
popup_unconstrain(popup);
|
||||||
|
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_layer_popup *sway_layer_popup =
|
||||||
|
wl_container_of(listener, sway_layer_popup, new_popup);
|
||||||
|
struct wlr_xdg_popup *wlr_popup = data;
|
||||||
|
create_popup(wlr_popup, LAYER_PARENT_POPUP, sway_layer_popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_new_popup(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_layer_surface *sway_layer_surface =
|
||||||
|
wl_container_of(listener, sway_layer_surface, new_popup);
|
||||||
|
struct wlr_xdg_popup *wlr_popup = data;
|
||||||
|
create_popup(wlr_popup, LAYER_PARENT_LAYER, sway_layer_surface);
|
||||||
|
}
|
||||||
|
|
||||||
struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
|
struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
|
||||||
struct wlr_layer_surface_v1 *layer_surface) {
|
struct wlr_layer_surface_v1 *layer_surface) {
|
||||||
return layer_surface->data;
|
return layer_surface->data;
|
||||||
|
@ -406,7 +531,8 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
||||||
wl_signal_add(&layer_surface->events.map, &sway_layer->map);
|
wl_signal_add(&layer_surface->events.map, &sway_layer->map);
|
||||||
sway_layer->unmap.notify = handle_unmap;
|
sway_layer->unmap.notify = handle_unmap;
|
||||||
wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap);
|
wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap);
|
||||||
// TODO: Listen for subsurfaces
|
sway_layer->new_popup.notify = handle_new_popup;
|
||||||
|
wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup);
|
||||||
|
|
||||||
sway_layer->layer_surface = layer_surface;
|
sway_layer->layer_surface = layer_surface;
|
||||||
layer_surface->data = sway_layer;
|
layer_surface->data = sway_layer;
|
||||||
|
|
|
@ -204,6 +204,36 @@ void output_layer_for_each_surface(struct sway_output *output,
|
||||||
output_surface_for_each_surface(output, wlr_layer_surface_v1->surface,
|
output_surface_for_each_surface(output, wlr_layer_surface_v1->surface,
|
||||||
layer_surface->geo.x, layer_surface->geo.y, iterator,
|
layer_surface->geo.x, layer_surface->geo.y, iterator,
|
||||||
user_data);
|
user_data);
|
||||||
|
|
||||||
|
struct wlr_xdg_popup *state;
|
||||||
|
wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) {
|
||||||
|
struct wlr_xdg_surface *popup = state->base;
|
||||||
|
if (!popup->configured) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double popup_sx, popup_sy;
|
||||||
|
popup_sx = layer_surface->geo.x +
|
||||||
|
popup->popup->geometry.x - popup->geometry.x;
|
||||||
|
popup_sy = layer_surface->geo.y +
|
||||||
|
popup->popup->geometry.y - popup->geometry.y;
|
||||||
|
|
||||||
|
struct wlr_surface *surface = popup->surface;
|
||||||
|
|
||||||
|
struct surface_iterator_data data = {
|
||||||
|
.user_iterator = iterator,
|
||||||
|
.user_data = user_data,
|
||||||
|
.output = output,
|
||||||
|
.ox = popup_sx,
|
||||||
|
.oy = popup_sy,
|
||||||
|
.width = surface->current.width,
|
||||||
|
.height = surface->current.height,
|
||||||
|
.rotation = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
wlr_xdg_surface_for_each_surface(
|
||||||
|
popup, output_for_each_surface_iterator, &data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,15 +39,12 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output,
|
||||||
struct wl_list *layer, double ox, double oy, double *sx, double *sy) {
|
struct wl_list *layer, double ox, double oy, double *sx, double *sy) {
|
||||||
struct sway_layer_surface *sway_layer;
|
struct sway_layer_surface *sway_layer;
|
||||||
wl_list_for_each_reverse(sway_layer, layer, link) {
|
wl_list_for_each_reverse(sway_layer, layer, link) {
|
||||||
struct wlr_surface *wlr_surface =
|
|
||||||
sway_layer->layer_surface->surface;
|
|
||||||
double _sx = ox - sway_layer->geo.x;
|
double _sx = ox - sway_layer->geo.x;
|
||||||
double _sy = oy - sway_layer->geo.y;
|
double _sy = oy - sway_layer->geo.y;
|
||||||
// TODO: Test popups/subsurfaces
|
struct wlr_surface *sub = wlr_layer_surface_v1_surface_at(
|
||||||
if (wlr_surface_point_accepts_input(wlr_surface, _sx, _sy)) {
|
sway_layer->layer_surface, _sx, _sy, sx, sy);
|
||||||
*sx = _sx;
|
if (sub) {
|
||||||
*sy = _sy;
|
return sub;
|
||||||
return wlr_surface;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Reference in a new issue