Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layer-shell: add support for popups #4307

Merged
merged 1 commit into from
Aug 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions include/sway/layers.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_layer_shell_v1.h>

enum layer_parent {
LAYER_PARENT_LAYER,
LAYER_PARENT_POPUP,
};

struct sway_layer_surface {
struct wlr_layer_surface_v1 *layer_surface;
struct wl_list link;
Expand All @@ -14,11 +19,26 @@ struct sway_layer_surface {
struct wl_listener unmap;
struct wl_listener surface_commit;
struct wl_listener output_destroy;
struct wl_listener new_popup;

bool configured;
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;
void arrange_layers(struct sway_output *output);

Expand Down
130 changes: 128 additions & 2 deletions sway/desktop/layer_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -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->unmap.link);
wl_list_remove(&sway_layer->surface_commit.link);
wl_list_remove(&sway_layer->new_popup.link);
if (sway_layer->layer_surface->output != NULL) {
struct sway_output *output = sway_layer->layer_surface->output->data;
if (output != NULL) {
Expand All @@ -338,7 +339,6 @@ static void handle_map(struct wl_listener *listener, void *data) {
struct sway_output *output = sway_layer->layer_surface->output->data;
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
sway_layer->layer_surface->surface, true);
// TODO: send enter to subsurfaces and popups
wlr_surface_send_enter(sway_layer->layer_surface->surface,
sway_layer->layer_surface->output);
cursor_rebase_all();
Expand All @@ -350,6 +350,131 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
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);
ddevault marked this conversation as resolved.
Show resolved Hide resolved
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 wlr_layer_surface_v1 *layer_surface) {
return layer_surface->data;
Expand Down Expand Up @@ -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);
sway_layer->unmap.notify = handle_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;
layer_surface->data = sway_layer;
Expand Down
30 changes: 30 additions & 0 deletions sway/desktop/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
layer_surface->geo.x, layer_surface->geo.y, iterator,
user_data);

struct wlr_xdg_popup *state;
wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) {
ddevault marked this conversation as resolved.
Show resolved Hide resolved
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);
}
}
}

Expand Down
11 changes: 4 additions & 7 deletions sway/input/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 sway_layer_surface *sway_layer;
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 _sy = oy - sway_layer->geo.y;
// TODO: Test popups/subsurfaces
if (wlr_surface_point_accepts_input(wlr_surface, _sx, _sy)) {
*sx = _sx;
*sy = _sy;
return wlr_surface;
struct wlr_surface *sub = wlr_layer_surface_v1_surface_at(
sway_layer->layer_surface, _sx, _sy, sx, sy);
if (sub) {
return sub;
}
}
return NULL;
Expand Down