From 6b7b64ec1eed0eb2d02c3de69f4352c21ed3c288 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 14 Apr 2018 15:47:51 -0400 Subject: Generalize xdg-shell popups and add to layer-shell --- include/wlr/types/wlr_layer_shell.h | 2 ++ include/wlr/types/wlr_xdg_shell.h | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/wlr/types/wlr_layer_shell.h b/include/wlr/types/wlr_layer_shell.h index 79b3a4ea..4b3e4e1c 100644 --- a/include/wlr/types/wlr_layer_shell.h +++ b/include/wlr/types/wlr_layer_shell.h @@ -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; diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 5046339a..cf96df4a 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -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); -- cgit v1.2.3 From d3cdb00208f119e1e2a2fc1f1733e6eff6d47da5 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 14 Apr 2018 16:50:05 -0400 Subject: Add (shitty) support for popups to layer example --- examples/layer-shell.c | 101 ++++++++++++++++++++++++++++++++++---- include/wlr/types/wlr_xdg_shell.h | 2 + types/wlr_layer_shell.c | 2 +- types/wlr_xdg_shell.c | 15 ++++-- 4 files changed, 106 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 245d762f..eee90b73 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -1,4 +1,9 @@ #define _POSIX_C_SOURCE 199309L +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif #include #include #include @@ -13,15 +18,19 @@ #include #include #include "wlr-layer-shell-unstable-v1-client-protocol.h" +#include "xdg-shell-client-protocol.h" + +static struct wl_display *display; +static struct wl_compositor *compositor; +static struct wl_seat *seat; +static struct wl_shm *shm; +static struct wl_pointer *pointer; +static struct wl_keyboard *keyboard; +static struct xdg_wm_base *xdg_wm_base; +static struct zwlr_layer_shell_v1 *layer_shell; -static struct wl_compositor *compositor = NULL; -static struct wl_seat *seat = NULL; -static struct wl_shm *shm = NULL; -static struct wl_pointer *pointer = NULL; -static struct wl_keyboard *keyboard = NULL; -static struct zwlr_layer_shell_v1 *layer_shell = NULL; struct zwlr_layer_surface_v1 *layer_surface; -static struct wl_output *wl_output = NULL; +static struct wl_output *wl_output; struct wl_surface *wl_surface; struct wlr_egl egl; @@ -30,6 +39,9 @@ struct wlr_egl_surface *egl_surface; struct wl_callback *frame_callback; static uint32_t output = UINT32_MAX; +struct xdg_surface *popup_surface; +struct xdg_popup *popup; + static uint32_t layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; static uint32_t anchor = 0; static uint32_t width = 256, height = 256; @@ -121,6 +133,71 @@ static void draw(void) { demo.last_frame = ts; } +static void xdg_surface_handle_configure(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) { + xdg_surface_ack_configure(xdg_surface, serial); + // Whatever +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_handle_configure, +}; + +static void xdg_popup_configure(void *data, struct xdg_popup *xdg_popup, + int32_t x, int32_t y, int32_t width, int32_t height) { + // Meh. +} + +static void xdg_popup_done(void *data, struct xdg_popup *xdg_popup) { + // We leak the surface, but who cares + xdg_popup_destroy(popup); + popup = NULL; +} + +static const struct xdg_popup_listener xdg_popup_listener = { + .configure = xdg_popup_configure, + .popup_done = xdg_popup_done, +}; + +static void create_popup() { + if (popup) { + return; + } + struct wl_surface *surface = wl_compositor_create_surface(compositor); + assert(xdg_wm_base && surface); + struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface( + xdg_wm_base, surface); + struct xdg_positioner *xdg_positioner = xdg_wm_base_create_positioner( + xdg_wm_base); + assert(xdg_surface && xdg_positioner); + + xdg_positioner_set_size(xdg_positioner, 256, 256); + xdg_positioner_set_anchor_rect(xdg_positioner, 0, 0, width, height); + + popup = xdg_surface_get_popup(xdg_surface, NULL, xdg_positioner); + assert(popup); + + zwlr_layer_surface_v1_get_popup(layer_surface, popup); + + xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL); + xdg_popup_add_listener(popup, &xdg_popup_listener, NULL); + + wl_surface_commit(surface); + wl_display_roundtrip(display); + + struct wl_egl_window *egl_window; + struct wlr_egl_surface *egl_surface; + egl_window = wl_egl_window_create(surface, 256, 256); + assert(egl_window); + egl_surface = wlr_egl_create_surface(&egl, egl_window); + assert(egl_surface); + + eglMakeCurrent(egl.display, egl_surface, egl_surface, egl.context); + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + eglSwapBuffers(egl.display, egl_surface); +} + static void layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t w, uint32_t h) { @@ -172,6 +249,9 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { if (state == WL_POINTER_BUTTON_STATE_PRESSED) { buttons++; + if (button == BTN_RIGHT) { + create_popup(); + } } else { buttons--; } @@ -277,7 +357,7 @@ const struct wl_seat_listener seat_listener = { static void handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { - if (strcmp(interface, "wl_compositor") == 0) { + if (strcmp(interface, wl_compositor_interface.name) == 0) { compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1); } else if (strcmp(interface, wl_shm_interface.name) == 0) { @@ -299,6 +379,9 @@ static void handle_global(void *data, struct wl_registry *registry, } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { layer_shell = wl_registry_bind( registry, name, &zwlr_layer_shell_v1_interface, 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + xdg_wm_base = wl_registry_bind( + registry, name, &xdg_wm_base_interface, 1); } } @@ -407,7 +490,7 @@ int main(int argc, char **argv) { } } - struct wl_display *display = wl_display_connect(NULL); + display = wl_display_connect(NULL); if (display == NULL) { fprintf(stderr, "Failed to create display\n"); return 1; diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index cf96df4a..b05dcac1 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -183,6 +183,8 @@ 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_xdg_surface *wlr_xdg_surface_from_popup_resource( + struct wl_resource *resource); struct wlr_box wlr_xdg_popup_get_geometry(struct wlr_xdg_popup *popup); diff --git a/types/wlr_layer_shell.c b/types/wlr_layer_shell.c index 7e603118..29e44827 100644 --- a/types/wlr_layer_shell.c +++ b/types/wlr_layer_shell.c @@ -137,7 +137,7 @@ static void layer_surface_handle_get_popup(struct wl_client *client, struct wlr_layer_surface *parent = layer_surface_from_resource(layer_resource); struct wlr_xdg_surface *popup_surface = - wlr_xdg_surface_from_resource(popup_resource); + wlr_xdg_surface_from_popup_resource(popup_resource); assert(popup_surface->role == WLR_XDG_SURFACE_ROLE_POPUP); struct wlr_xdg_popup *popup = popup_surface->popup; diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 080d57a4..66dac02a 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -527,7 +527,7 @@ struct wlr_box wlr_xdg_popup_get_geometry(struct wlr_xdg_popup *popup) { static const struct xdg_popup_interface xdg_popup_implementation; -static struct wlr_xdg_surface *xdg_surface_from_xdg_popup_resource( +struct wlr_xdg_surface *wlr_xdg_surface_from_popup_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &xdg_popup_interface, &xdg_popup_implementation)); @@ -538,7 +538,7 @@ static void xdg_popup_handle_grab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_popup_resource(resource); + wlr_xdg_surface_from_popup_resource(resource); struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); @@ -574,7 +574,7 @@ static void xdg_popup_handle_grab(struct wl_client *client, static void xdg_popup_handle_destroy(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_popup_resource(resource); + wlr_xdg_surface_from_popup_resource(resource); if (!wl_list_empty(&surface->popups)) { wl_resource_post_error(surface->client->resource, @@ -593,7 +593,7 @@ static const struct xdg_popup_interface xdg_popup_implementation = { static void xdg_popup_resource_destroy(struct wl_resource *resource) { struct wlr_xdg_surface *surface = - xdg_surface_from_xdg_popup_resource(resource); + wlr_xdg_surface_from_popup_resource(resource); if (surface != NULL) { xdg_popup_destroy(surface); } @@ -1281,6 +1281,13 @@ static void wlr_xdg_surface_popup_committed( struct wlr_xdg_surface *surface) { assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); + if (!surface->popup->parent) { + wl_resource_post_error(surface->resource, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, + "xdg_popup has no parent"); + return; + } + if (!surface->popup->committed) { wlr_xdg_surface_schedule_configure(surface); surface->popup->committed = true; -- cgit v1.2.3 From 278aa846195ceb8ea85c181aba21e0befbcce5de Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 14 Apr 2018 20:36:01 -0400 Subject: Basic layer popup rendering --- include/wlr/types/wlr_layer_shell.h | 4 ++++ rootston/output.c | 2 ++ types/wlr_layer_shell.c | 46 +++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) (limited to 'include') diff --git a/include/wlr/types/wlr_layer_shell.h b/include/wlr/types/wlr_layer_shell.h index 4b3e4e1c..6040478d 100644 --- a/include/wlr/types/wlr_layer_shell.h +++ b/include/wlr/types/wlr_layer_shell.h @@ -109,4 +109,8 @@ bool wlr_surface_is_layer_surface(struct wlr_surface *surface); struct wlr_layer_surface *wlr_layer_surface_from_wlr_surface( struct wlr_surface *surface); +/* Calls the iterator function for each sub-surface and popup of this surface */ +void wlr_layer_surface_for_each_surface(struct wlr_layer_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data); + #endif diff --git a/rootston/output.c b/rootston/output.c index 791b2819..48b20466 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -366,6 +366,8 @@ static void render_layer(struct roots_output *output, roots_surface->geo.x + output_layout_box->x, roots_surface->geo.y + output_layout_box->y, 0, &data->layout, render_surface, data); + + wlr_layer_surface_for_each_surface(layer, render_surface, data); } } diff --git a/types/wlr_layer_shell.c b/types/wlr_layer_shell.c index 29e44827..9121b1d2 100644 --- a/types/wlr_layer_shell.c +++ b/types/wlr_layer_shell.c @@ -452,3 +452,49 @@ void wlr_layer_shell_destroy(struct wlr_layer_shell *layer_shell) { wl_global_destroy(layer_shell->wl_global); free(layer_shell); } + +struct layer_surface_iterator_data { + wlr_surface_iterator_func_t user_iterator; + void *user_data; + int x, y; +}; + +static void layer_surface_iterator(struct wlr_surface *surface, + int sx, int sy, void *data) { + struct layer_surface_iterator_data *iter_data = data; + iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy, + iter_data->user_data); +} + +static void layer_surface_for_each_surface(struct wlr_layer_surface *surface, + int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { + struct layer_surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .x = x, .y = y, + }; + wlr_surface_for_each_surface(surface->surface, + layer_surface_iterator, &data); + + struct wlr_xdg_popup *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface *popup = popup_state->base; + if (!popup->configured) { + continue; + } + + double popup_sx, popup_sy; + popup_sx = popup->geometry.x; + popup_sy = popup->geometry.y; + + iterator(popup->surface, data.x + popup_sx, + data.y + popup_sy, user_data); + + wlr_xdg_surface_for_each_surface(popup, layer_surface_iterator, &data); + } +} + +void wlr_layer_surface_for_each_surface(struct wlr_layer_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data) { + layer_surface_for_each_surface(surface, 0, 0, iterator, user_data); +} -- cgit v1.2.3 From 2e3d901ac56f962d2ac9aab8b86c01b388c593f5 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 14 Apr 2018 21:17:40 -0400 Subject: Forward-port xdg-shell-v6 positioner improvements --- examples/layer-shell.c | 17 +++-- include/wlr/types/wlr_xdg_shell.h | 25 +++++-- types/wlr_layer_shell.c | 2 +- types/wlr_xdg_shell.c | 137 +++++++++++++------------------------- types/wlr_xdg_shell_v6.c | 2 - 5 files changed, 79 insertions(+), 104 deletions(-) (limited to 'include') diff --git a/examples/layer-shell.c b/examples/layer-shell.c index eee90b73..ac6e8a9e 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -165,14 +165,19 @@ static void create_popup() { } struct wl_surface *surface = wl_compositor_create_surface(compositor); assert(xdg_wm_base && surface); - struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface( - xdg_wm_base, surface); - struct xdg_positioner *xdg_positioner = xdg_wm_base_create_positioner( - xdg_wm_base); + struct xdg_surface *xdg_surface = + xdg_wm_base_get_xdg_surface(xdg_wm_base, surface); + struct xdg_positioner *xdg_positioner = + xdg_wm_base_create_positioner(xdg_wm_base); assert(xdg_surface && xdg_positioner); xdg_positioner_set_size(xdg_positioner, 256, 256); - xdg_positioner_set_anchor_rect(xdg_positioner, 0, 0, width, height); + xdg_positioner_set_offset(xdg_positioner, 0, 0); + xdg_positioner_set_anchor_rect(xdg_positioner, cur_x, cur_y, 1, 1); + xdg_positioner_set_anchor(xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); + xdg_positioner_set_gravity(xdg_positioner, XDG_POSITIONER_GRAVITY_TOP_LEFT); + xdg_positioner_set_constraint_adjustment(xdg_positioner, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE); popup = xdg_surface_get_popup(xdg_surface, NULL, xdg_positioner); assert(popup); @@ -185,6 +190,8 @@ static void create_popup() { wl_surface_commit(surface); wl_display_roundtrip(display); + xdg_positioner_destroy(xdg_positioner); + struct wl_egl_window *egl_window; struct wlr_egl_surface *egl_surface; egl_window = wl_egl_window_create(surface, 256, 256); diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index b05dcac1..809d6390 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -1,9 +1,9 @@ #ifndef WLR_TYPES_WLR_XDG_SHELL_H #define WLR_TYPES_WLR_XDG_SHELL_H - #include #include #include +#include "xdg-shell-protocol.h" struct wlr_xdg_shell { struct wl_global *wl_global; @@ -32,7 +32,22 @@ struct wlr_xdg_client { struct wl_event_source *ping_timer; }; -struct wlr_xdg_positioner; +struct wlr_xdg_positioner { + struct wl_resource *resource; + + struct wlr_box anchor_rect; + enum xdg_positioner_anchor anchor; + enum xdg_positioner_gravity gravity; + enum xdg_positioner_constraint_adjustment constraint_adjustment; + + struct { + int32_t width, height; + } size; + + struct { + int32_t x, y; + } offset; +}; struct wlr_xdg_popup { struct wlr_xdg_surface *base; @@ -43,11 +58,12 @@ struct wlr_xdg_popup { 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; + struct wlr_xdg_positioner positioner; + struct wl_list grab_link; // wlr_xdg_popup_grab::popups }; @@ -186,7 +202,8 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_resource( struct wlr_xdg_surface *wlr_xdg_surface_from_popup_resource( struct wl_resource *resource); -struct wlr_box wlr_xdg_popup_get_geometry(struct wlr_xdg_popup *popup); +struct wlr_box wlr_xdg_positioner_get_geometry( + struct wlr_xdg_positioner *positioner); /** * Send a ping to the surface. If the surface does not respond in a reasonable diff --git a/types/wlr_layer_shell.c b/types/wlr_layer_shell.c index 9121b1d2..5c709713 100644 --- a/types/wlr_layer_shell.c +++ b/types/wlr_layer_shell.c @@ -142,7 +142,7 @@ static void layer_surface_handle_get_popup(struct wl_client *client, 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); + popup->geometry = wlr_xdg_positioner_get_geometry(&popup->positioner); wl_list_insert(&parent->popups, &popup->link); wlr_signal_emit_safe(&parent->events.new_popup, popup); } diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 66dac02a..22d404a7 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -28,24 +28,11 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface( return (struct wlr_xdg_surface *)surface->role_data; } -struct wlr_xdg_positioner { +struct wlr_xdg_positioner_resource { struct wl_resource *resource; - - struct wlr_box anchor_rect; - enum xdg_positioner_anchor anchor; - enum xdg_positioner_gravity gravity; - enum xdg_positioner_constraint_adjustment constraint_adjustment; - - struct { - int32_t width, height; - } size; - - struct { - int32_t x, y; - } offset; + struct wlr_xdg_positioner attrs; }; - static void resource_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -301,7 +288,7 @@ static void xdg_surface_destroy(struct wlr_xdg_surface *surface) { static const struct xdg_positioner_interface xdg_positioner_implementation; -static struct wlr_xdg_positioner *xdg_positioner_from_resource( +static struct wlr_xdg_positioner_resource *xdg_positioner_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &xdg_positioner_interface, &xdg_positioner_implementation)); @@ -309,14 +296,14 @@ static struct wlr_xdg_positioner *xdg_positioner_from_resource( } static void xdg_positioner_destroy(struct wl_resource *resource) { - struct wlr_xdg_positioner *positioner = + struct wlr_xdg_positioner_resource *positioner = xdg_positioner_from_resource(resource); free(positioner); } static void xdg_positioner_handle_set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - struct wlr_xdg_positioner *positioner = + struct wlr_xdg_positioner_resource *positioner = xdg_positioner_from_resource(resource); if (width < 1 || height < 1) { @@ -326,14 +313,14 @@ static void xdg_positioner_handle_set_size(struct wl_client *client, return; } - positioner->size.width = width; - positioner->size.height = height; + positioner->attrs.size.width = width; + positioner->attrs.size.height = height; } static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wlr_xdg_positioner *positioner = + struct wlr_xdg_positioner_resource *positioner = xdg_positioner_from_resource(resource); if (width < 0 || height < 0) { @@ -343,15 +330,15 @@ static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client, return; } - positioner->anchor_rect.x = x; - positioner->anchor_rect.y = y; - positioner->anchor_rect.width = width; - positioner->anchor_rect.height = height; + positioner->attrs.anchor_rect.x = x; + positioner->attrs.anchor_rect.y = y; + positioner->attrs.anchor_rect.width = width; + positioner->attrs.anchor_rect.height = height; } static void xdg_positioner_handle_set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor) { - struct wlr_xdg_positioner *positioner = + struct wlr_xdg_positioner_resource *positioner = xdg_positioner_from_resource(resource); if (anchor > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) { @@ -361,12 +348,12 @@ static void xdg_positioner_handle_set_anchor(struct wl_client *client, return; } - positioner->anchor = anchor; + positioner->attrs.anchor = anchor; } static void xdg_positioner_handle_set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity) { - struct wlr_xdg_positioner *positioner = + struct wlr_xdg_positioner_resource *positioner = xdg_positioner_from_resource(resource); if (gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) { @@ -376,25 +363,25 @@ static void xdg_positioner_handle_set_gravity(struct wl_client *client, return; } - positioner->gravity = gravity; + positioner->attrs.gravity = gravity; } static void xdg_positioner_handle_set_constraint_adjustment( struct wl_client *client, struct wl_resource *resource, uint32_t constraint_adjustment) { - struct wlr_xdg_positioner *positioner = + struct wlr_xdg_positioner_resource *positioner = xdg_positioner_from_resource(resource); - positioner->constraint_adjustment = constraint_adjustment; + positioner->attrs.constraint_adjustment = constraint_adjustment; } static void xdg_positioner_handle_set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { - struct wlr_xdg_positioner *positioner = + struct wlr_xdg_positioner_resource *positioner = xdg_positioner_from_resource(resource); - positioner->offset.x = x; - positioner->offset.y = y; + positioner->attrs.offset.x = x; + positioner->attrs.offset.y = y; } static const struct xdg_positioner_interface @@ -412,16 +399,12 @@ static const struct xdg_positioner_interface static void xdg_shell_handle_create_positioner(struct wl_client *wl_client, struct wl_resource *resource, uint32_t id) { struct wlr_xdg_positioner *positioner = - calloc(1, sizeof(struct wlr_xdg_positioner)); + calloc(1, sizeof(struct wlr_xdg_positioner_resource)); if (positioner == NULL) { wl_client_post_no_memory(wl_client); return; } - /* set widths to detect improper usages of get_popup */ - positioner->size.width = -1; - positioner->anchor_rect.width = -1; - positioner->resource = wl_resource_create(wl_client, &xdg_positioner_interface, wl_resource_get_version(resource), @@ -437,9 +420,8 @@ static void xdg_shell_handle_create_positioner(struct wl_client *wl_client, positioner, xdg_positioner_destroy); } -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 wlr_xdg_positioner_get_geometry( + struct wlr_xdg_positioner *positioner) { struct wlr_box geometry = { .x = positioner->offset.x, .y = positioner->offset.y, @@ -447,71 +429,39 @@ struct wlr_box wlr_xdg_popup_get_geometry(struct wlr_xdg_popup *popup) { .height = positioner->size.height, }; - switch (positioner->anchor) { - case XDG_POSITIONER_ANCHOR_TOP: - case XDG_POSITIONER_ANCHOR_TOP_LEFT: - case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + if (positioner->anchor & XDG_POSITIONER_ANCHOR_TOP) { geometry.y += positioner->anchor_rect.y; - break; - case XDG_POSITIONER_ANCHOR_BOTTOM: - case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: - case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + } else if (positioner->anchor & XDG_POSITIONER_ANCHOR_BOTTOM) { geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height; - break; - default: + } else { geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height / 2; - break; } - switch (positioner->anchor) { - case XDG_POSITIONER_ANCHOR_LEFT: - case XDG_POSITIONER_ANCHOR_TOP_LEFT: - case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + if (positioner->anchor & XDG_POSITIONER_ANCHOR_LEFT) { geometry.x += positioner->anchor_rect.x; - break; - case XDG_POSITIONER_ANCHOR_RIGHT: - case XDG_POSITIONER_ANCHOR_TOP_RIGHT: - case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + } else if (positioner->anchor & XDG_POSITIONER_ANCHOR_RIGHT) { geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width; - break; - default: + } else { geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width / 2; - break; } - switch (positioner->gravity) { - case XDG_POSITIONER_GRAVITY_TOP: - case XDG_POSITIONER_GRAVITY_TOP_LEFT: - case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + if (positioner->gravity & XDG_POSITIONER_GRAVITY_TOP) { geometry.y -= geometry.height; - break; - case XDG_POSITIONER_GRAVITY_BOTTOM: - case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: - case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + } else if (positioner->gravity & XDG_POSITIONER_GRAVITY_BOTTOM) { geometry.y = geometry.y; - break; - default: + } else { geometry.y -= geometry.height / 2; - break; } - switch (positioner->gravity) { - case XDG_POSITIONER_GRAVITY_LEFT: - case XDG_POSITIONER_GRAVITY_TOP_LEFT: - case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + if (positioner->gravity & XDG_POSITIONER_GRAVITY_LEFT) { geometry.x -= geometry.width; - break; - case XDG_POSITIONER_GRAVITY_RIGHT: - case XDG_POSITIONER_GRAVITY_TOP_RIGHT: - case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + } else if (positioner->gravity & XDG_POSITIONER_GRAVITY_RIGHT) { geometry.x = geometry.x; - break; - default: + } else { geometry.x -= geometry.width / 2; - break; } if (positioner->constraint_adjustment == @@ -519,8 +469,6 @@ struct wlr_box wlr_xdg_popup_get_geometry(struct wlr_xdg_popup *popup) { return geometry; } - // TODO: add compositor policy configuration and the code here - return geometry; } @@ -620,10 +568,11 @@ static void xdg_surface_handle_get_popup(struct wl_client *client, wlr_xdg_surface_from_resource(resource); struct wlr_xdg_surface *parent = wlr_xdg_surface_from_resource(parent_resource); - struct wlr_xdg_positioner *positioner = + struct wlr_xdg_positioner_resource *positioner = xdg_positioner_from_resource(positioner_resource); - if (positioner->size.width == -1 || positioner->anchor_rect.width == -1) { + if (positioner->attrs.size.width == 0 || + positioner->attrs.anchor_rect.width == 0) { wl_resource_post_error(resource, XDG_WM_BASE_ERROR_INVALID_POSITIONER, "positioner object is not complete"); @@ -652,7 +601,10 @@ static void xdg_surface_handle_get_popup(struct wl_client *client, surface->role = WLR_XDG_SURFACE_ROLE_POPUP; surface->popup->base = surface; - surface->popup->positioner = positioner; + + // positioner properties + memcpy(&surface->popup->positioner, &positioner->attrs, + sizeof(struct wlr_xdg_positioner)); wl_resource_set_implementation(surface->popup->resource, &xdg_popup_implementation, surface, @@ -660,7 +612,8 @@ static void xdg_surface_handle_get_popup(struct wl_client *client, if (parent) { surface->popup->parent = parent->surface; - surface->popup->geometry = wlr_xdg_popup_get_geometry(surface->popup); + surface->popup->geometry = + wlr_xdg_positioner_get_geometry(&positioner->attrs); wl_list_insert(&parent->popups, &surface->popup->link); wlr_signal_emit_safe(&parent->events.new_popup, surface->popup); } diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 22b387f1..2d0fbe29 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -486,8 +486,6 @@ struct wlr_box wlr_xdg_positioner_v6_get_geometry( return geometry; } - // TODO: add compositor policy configuration and the code here - return geometry; } -- cgit v1.2.3 From 0a0627f5d03afdaef2251e2442a3ff3285cd8356 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 14 Apr 2018 21:34:50 -0400 Subject: Finish forward-porting @acrisci's positioner work --- examples/layer-shell.c | 5 +- include/wlr/types/wlr_xdg_shell.h | 40 ++++++ rootston/xdg_shell.c | 56 ++++++++ types/wlr_xdg_shell.c | 262 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 360 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/examples/layer-shell.c b/examples/layer-shell.c index ac6e8a9e..56fa28f7 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -145,7 +145,8 @@ static const struct xdg_surface_listener xdg_surface_listener = { static void xdg_popup_configure(void *data, struct xdg_popup *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height) { - // Meh. + wlr_log(L_DEBUG, "Popup configured %dx%d@%d,%d", + width, height, x, y); } static void xdg_popup_done(void *data, struct xdg_popup *xdg_popup) { @@ -176,8 +177,6 @@ static void create_popup() { xdg_positioner_set_anchor_rect(xdg_positioner, cur_x, cur_y, 1, 1); xdg_positioner_set_anchor(xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); xdg_positioner_set_gravity(xdg_positioner, XDG_POSITIONER_GRAVITY_TOP_LEFT); - xdg_positioner_set_constraint_adjustment(xdg_positioner, - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE); popup = xdg_surface_get_popup(xdg_surface, NULL, xdg_positioner); assert(popup); diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 809d6390..ead4613a 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -258,6 +258,46 @@ 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); +/** + * Get the geometry for this positioner based on the anchor rect, gravity, and + * size of this positioner. + */ +struct wlr_box wlr_xdg_positioner_get_geometry( + struct wlr_xdg_positioner *positioner); + +/** + * Get the anchor point for this popup in the toplevel parent's coordinate system. + */ +void wlr_xdg_popup_get_anchor_point(struct wlr_xdg_popup *popup, + int *toplevel_sx, int *toplevel_sy); + +/** + * Convert the given coordinates in the popup coordinate system to the toplevel + * surface coordinate system. + */ +void wlr_xdg_popup_get_toplevel_coords(struct wlr_xdg_popup *popup, + int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy); + +/** + * Set the geometry of this popup to unconstrain it according to its + * xdg-positioner rules. The box should be in the popup's root toplevel parent + * surface coordinate system. + */ +void wlr_xdg_popup_unconstrain_from_box(struct wlr_xdg_popup *popup, + struct wlr_box *toplevel_sx_box); + +/** + Invert the right/left anchor and gravity for this positioner. This can be + used to "flip" the positioner around the anchor rect in the x direction. + */ +void wlr_positioner_invert_x(struct wlr_xdg_positioner *positioner); + +/** + Invert the top/bottom anchor and gravity for this positioner. This can be + used to "flip" the positioner around the anchor rect in the y direction. + */ +void wlr_positioner_invert_y(struct wlr_xdg_positioner *positioner); + /** * Find a surface within this xdg-surface tree at the given surface-local * coordinates. Returns the surface and coordinates in the leaf surface diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index 927bd018..bd670a87 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -48,6 +48,59 @@ static void popup_handle_new_popup(struct wl_listener *listener, void *data) { popup_create(popup->view_child.view, wlr_popup); } +static void popup_unconstrain(struct roots_xdg_popup *popup) { + // get the output of the popup's positioner anchor point and convert it to + // the toplevel parent's coordinate system and then pass it to + // wlr_xdg_popup_v6_unconstrain_from_box + + // TODO: unconstrain popups for rotated windows + if (popup->view_child.view->rotation != 0.0) { + return; + } + + struct roots_view *view = popup->view_child.view; + struct wlr_output_layout *layout = view->desktop->layout; + struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; + + int anchor_lx, anchor_ly; + wlr_xdg_popup_get_anchor_point(wlr_popup, &anchor_lx, &anchor_ly); + + int popup_lx, popup_ly; + wlr_xdg_popup_get_toplevel_coords(wlr_popup, wlr_popup->geometry.x, + wlr_popup->geometry.y, &popup_lx, &popup_ly); + popup_lx += view->x; + popup_ly += view->y; + + anchor_lx += popup_lx; + anchor_ly += popup_ly; + + double dest_x = 0, dest_y = 0; + wlr_output_layout_closest_point(layout, NULL, anchor_lx, anchor_ly, + &dest_x, &dest_y); + + struct wlr_output *output = + wlr_output_layout_output_at(layout, dest_x, dest_y); + + if (output == NULL) { + return; + } + + int width = 0, height = 0; + wlr_output_effective_resolution(output, &width, &height); + + // the output box expressed in the coordinate system of the toplevel parent + // of the popup + struct wlr_box output_toplevel_sx_box = { + .x = output->lx - view->x, + .y = output->ly - view->y, + .width = width, + .height = height + }; + + wlr_xdg_popup_unconstrain_from_box( + popup->wlr_popup, &output_toplevel_sx_box); +} + static struct roots_xdg_popup *popup_create(struct roots_view *view, struct wlr_xdg_popup *wlr_popup) { struct roots_xdg_popup *popup = @@ -66,6 +119,9 @@ static struct roots_xdg_popup *popup_create(struct roots_view *view, wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap); 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; } diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 22d404a7..78b18563 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -1608,6 +1608,268 @@ struct wlr_surface *wlr_xdg_surface_surface_at( return wlr_surface_surface_at(surface->surface, sx, sy, sub_x, sub_y); } +void wlr_xdg_popup_get_anchor_point(struct wlr_xdg_popup *popup, + int *root_sx, int *root_sy) { + struct wlr_box rect = popup->positioner.anchor_rect; + enum xdg_positioner_anchor anchor = popup->positioner.anchor; + int sx = 0, sy = 0; + + if (anchor == XDG_POSITIONER_ANCHOR_NONE) { + sx = (rect.x + rect.width) / 2; + sy = (rect.y + rect.height) / 2; + } else if (anchor == XDG_POSITIONER_ANCHOR_TOP) { + sx = (rect.x + rect.width) / 2; + sy = rect.y; + } else if (anchor == XDG_POSITIONER_ANCHOR_BOTTOM) { + sx = (rect.x + rect.width) / 2; + sy = rect.y + rect.height; + } else if (anchor == XDG_POSITIONER_ANCHOR_LEFT) { + sx = rect.x; + sy = (rect.y + rect.height) / 2; + } else if (anchor == XDG_POSITIONER_ANCHOR_RIGHT) { + sx = rect.x + rect.width; + sy = (rect.y + rect.height) / 2; + } else if (anchor == (XDG_POSITIONER_ANCHOR_TOP | + XDG_POSITIONER_ANCHOR_LEFT)) { + sx = rect.x; + sy = rect.y; + } else if (anchor == (XDG_POSITIONER_ANCHOR_TOP | + XDG_POSITIONER_ANCHOR_RIGHT)) { + sx = rect.x + rect.width; + sy = rect.y; + } else if (anchor == (XDG_POSITIONER_ANCHOR_BOTTOM | + XDG_POSITIONER_ANCHOR_LEFT)) { + sx = rect.x; + sy = rect.y + rect.height; + } else if (anchor == (XDG_POSITIONER_ANCHOR_BOTTOM | + XDG_POSITIONER_ANCHOR_RIGHT)) { + sx = rect.x + rect.width; + sy = rect.y + rect.height; + } + + *root_sx = sx; + *root_sy = sy; +} + +void wlr_xdg_popup_get_toplevel_coords(struct wlr_xdg_popup *popup, + int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy) { + 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; + while (parent != NULL && parent->role == WLR_XDG_SURFACE_ROLE_POPUP) { + popup_sx += parent->popup->geometry.x; + popup_sy += parent->popup->geometry.y; + parent = parent->popup->parent->role_data; + } + + assert(parent); + + *toplevel_sx = popup_sx + parent->geometry.x; + *toplevel_sy = popup_sy + parent->geometry.y; + +} + +static void wlr_xdg_popup_box_constraints(struct wlr_xdg_popup *popup, + struct wlr_box *toplevel_sx_box, int *offset_x, int *offset_y) { + int popup_width = popup->geometry.width; + int popup_height = popup->geometry.height; + int anchor_sx = 0, anchor_sy = 0; + wlr_xdg_popup_get_anchor_point(popup, &anchor_sx, &anchor_sy); + int popup_sx = 0, popup_sy = 0; + wlr_xdg_popup_get_toplevel_coords(popup, popup->geometry.x, + popup->geometry.y, &popup_sx, &popup_sy); + *offset_x = 0, *offset_y = 0; + + if (popup_sx < toplevel_sx_box->x) { + *offset_x = toplevel_sx_box->x - popup_sx; + } else if (popup_sx + popup_width > + toplevel_sx_box->x + toplevel_sx_box->width) { + *offset_x = toplevel_sx_box->x + toplevel_sx_box->width - + (popup_sx + popup_width); + } + + if (popup_sy < toplevel_sx_box->y) { + *offset_y = toplevel_sx_box->y - popup_sy; + } else if (popup_sy + popup_height > + toplevel_sx_box->y + toplevel_sx_box->height) { + *offset_y = toplevel_sx_box->y + toplevel_sx_box->height - + (popup_sy + popup_height); + } +} + +static bool wlr_xdg_popup_unconstrain_flip(struct wlr_xdg_popup *popup, + struct wlr_box *toplevel_sx_box) { + int offset_x = 0, offset_y = 0; + wlr_xdg_popup_box_constraints(popup, toplevel_sx_box, + &offset_x, &offset_y); + + if (!offset_x && !offset_y) { + return true; + } + + bool flip_x = offset_x && + (popup->positioner.constraint_adjustment & + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X); + + bool flip_y = offset_y && + (popup->positioner.constraint_adjustment & + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y); + + if (flip_x) { + wlr_positioner_invert_x(&popup->positioner); + } + if (flip_y) { + wlr_positioner_invert_y(&popup->positioner); + } + + popup->geometry = + wlr_xdg_positioner_get_geometry(&popup->positioner); + + wlr_xdg_popup_box_constraints(popup, toplevel_sx_box, + &offset_x, &offset_y); + + if (!offset_x && !offset_y) { + // no longer constrained + return true; + } + + // revert the positioner back if it didn't fix it and go to the next part + if (flip_x) { + wlr_positioner_invert_x(&popup->positioner); + } + if (flip_y) { + wlr_positioner_invert_y(&popup->positioner); + } + + popup->geometry = + wlr_xdg_positioner_get_geometry(&popup->positioner); + + return false; +} + +static bool wlr_xdg_popup_unconstrain_slide(struct wlr_xdg_popup *popup, + struct wlr_box *toplevel_sx_box) { + int offset_x = 0, offset_y = 0; + wlr_xdg_popup_box_constraints(popup, toplevel_sx_box, + &offset_x, &offset_y); + + if (!offset_x && !offset_y) { + return true; + } + + bool slide_x = offset_x && + (popup->positioner.constraint_adjustment & + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X); + + bool slide_y = offset_x && + (popup->positioner.constraint_adjustment & + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); + + if (slide_x) { + popup->geometry.x += offset_x; + } + + if (slide_y) { + popup->geometry.y += offset_y; + } + + int toplevel_x = 0, toplevel_y = 0; + wlr_xdg_popup_get_toplevel_coords(popup, popup->geometry.x, + popup->geometry.y, &toplevel_x, &toplevel_y); + + if (slide_x && toplevel_x < toplevel_sx_box->x) { + popup->geometry.x += toplevel_sx_box->x - toplevel_x; + } + if (slide_y && toplevel_y < toplevel_sx_box->y) { + popup->geometry.y += toplevel_sx_box->y - toplevel_y; + } + + wlr_xdg_popup_box_constraints(popup, toplevel_sx_box, + &offset_x, &offset_y); + + return !offset_x && !offset_y; +} + +static bool wlr_xdg_popup_unconstrain_resize(struct wlr_xdg_popup *popup, + struct wlr_box *toplevel_sx_box) { + int offset_x, offset_y; + wlr_xdg_popup_box_constraints(popup, toplevel_sx_box, + &offset_x, &offset_y); + + if (!offset_x && !offset_y) { + return true; + } + + bool resize_x = offset_x && + (popup->positioner.constraint_adjustment & + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X); + + bool resize_y = offset_x && + (popup->positioner.constraint_adjustment & + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y); + + if (resize_x) { + popup->geometry.width -= offset_x; + } + if (resize_y) { + popup->geometry.height -= offset_y; + } + + wlr_xdg_popup_box_constraints(popup, toplevel_sx_box, + &offset_y, &offset_y); + + return !offset_x && !offset_y; +} + +void wlr_xdg_popup_unconstrain_from_box(struct wlr_xdg_popup *popup, + struct wlr_box *toplevel_sx_box) { + if (wlr_xdg_popup_unconstrain_flip(popup, toplevel_sx_box)) { + return; + } + if (wlr_xdg_popup_unconstrain_slide(popup, toplevel_sx_box)) { + return; + } + if (wlr_xdg_popup_unconstrain_resize(popup, toplevel_sx_box)) { + return; + } +} + +void wlr_positioner_invert_x(struct wlr_xdg_positioner *positioner) { + if (positioner->anchor & XDG_POSITIONER_ANCHOR_LEFT) { + positioner->anchor &= ~XDG_POSITIONER_ANCHOR_LEFT; + positioner->anchor |= XDG_POSITIONER_ANCHOR_RIGHT; + } else if (positioner->anchor & XDG_POSITIONER_ANCHOR_RIGHT) { + positioner->anchor &= ~XDG_POSITIONER_ANCHOR_RIGHT; + positioner->anchor |= XDG_POSITIONER_ANCHOR_LEFT; + } + + if (positioner->gravity & XDG_POSITIONER_GRAVITY_RIGHT) { + positioner->gravity &= ~XDG_POSITIONER_GRAVITY_RIGHT; + positioner->gravity |= XDG_POSITIONER_GRAVITY_LEFT; + } else if (positioner->gravity & XDG_POSITIONER_GRAVITY_LEFT) { + positioner->gravity &= ~XDG_POSITIONER_GRAVITY_LEFT; + positioner->gravity |= XDG_POSITIONER_GRAVITY_RIGHT; + } +} + +void wlr_positioner_invert_y( + struct wlr_xdg_positioner *positioner) { + if (positioner->anchor & XDG_POSITIONER_ANCHOR_TOP) { + positioner->anchor &= ~XDG_POSITIONER_ANCHOR_TOP; + positioner->anchor |= XDG_POSITIONER_ANCHOR_BOTTOM; + } else if (positioner->anchor & XDG_POSITIONER_ANCHOR_BOTTOM) { + positioner->anchor &= ~XDG_POSITIONER_ANCHOR_BOTTOM; + positioner->anchor |= XDG_POSITIONER_ANCHOR_TOP; + } + + if (positioner->gravity & XDG_POSITIONER_GRAVITY_TOP) { + positioner->gravity &= ~XDG_POSITIONER_GRAVITY_TOP; + positioner->gravity |= XDG_POSITIONER_GRAVITY_BOTTOM; + } else if (positioner->gravity & XDG_POSITIONER_GRAVITY_BOTTOM) { + positioner->gravity &= ~XDG_POSITIONER_GRAVITY_BOTTOM; + positioner->gravity |= XDG_POSITIONER_GRAVITY_TOP; + } +} struct xdg_surface_iterator_data { wlr_surface_iterator_func_t user_iterator; -- cgit v1.2.3 From ad22e023103fc737188cac0bb468eedbc4d3982e Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Thu, 19 Apr 2018 18:25:19 +0200 Subject: rootston: Damage layer-shell popups --- include/rootston/layers.h | 10 ++++++ rootston/layer_shell.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) (limited to 'include') diff --git a/include/rootston/layers.h b/include/rootston/layers.h index 0e5164bb..9eab53ca 100644 --- a/include/rootston/layers.h +++ b/include/rootston/layers.h @@ -14,11 +14,21 @@ struct roots_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 roots_layer_popup { + struct roots_layer_surface *parent; + struct wlr_xdg_popup *wlr_popup; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener destroy; + struct wl_listener commit; +}; + struct roots_output; void arrange_layers(struct roots_output *output); diff --git a/rootston/layer_shell.c b/rootston/layer_shell.c index b6f7ba4c..071467e0 100644 --- a/rootston/layer_shell.c +++ b/rootston/layer_shell.c @@ -292,6 +292,82 @@ static void handle_unmap(struct wl_listener *listener, void *data) { unmap(layer->layer_surface); } +static void popup_handle_map(struct wl_listener *listener, void *data) { + struct roots_layer_popup *popup = wl_container_of(listener, popup, map); + struct roots_layer_surface *layer = popup->parent; + struct wlr_output *wlr_output = layer->layer_surface->output; + struct roots_output *output = wlr_output->data; + struct wlr_box geom; + memcpy(&geom, &popup->wlr_popup->geometry, sizeof(struct wlr_box)); + geom.x += layer->geo.x; + geom.y += layer->geo.y; + wlr_output_damage_add_box(output->damage, &geom); +} + +static void popup_handle_unmap(struct wl_listener *listener, void *data) { + struct roots_layer_popup *popup = wl_container_of(listener, popup, unmap); + struct roots_layer_surface *layer = popup->parent; + struct wlr_output *wlr_output = layer->layer_surface->output; + struct roots_output *output = wlr_output->data; + struct wlr_box geom; + memcpy(&geom, &popup->wlr_popup->geometry, sizeof(struct wlr_box)); + geom.x += layer->geo.x; + geom.y += layer->geo.y; + wlr_output_damage_add_box(output->damage, &geom); +} + +static void popup_handle_commit(struct wl_listener *listener, void *data) { + struct roots_layer_popup *popup = wl_container_of(listener, popup, commit); + struct roots_layer_surface *layer = popup->parent; + struct wlr_output *wlr_output = layer->layer_surface->output; + struct roots_output *output = wlr_output->data; + struct wlr_box geom; + memcpy(&geom, &popup->wlr_popup->geometry, sizeof(struct wlr_box)); + geom.x += layer->geo.x; + geom.y += layer->geo.y; + wlr_output_damage_add_box(output->damage, &geom); +} + +static void popup_handle_destroy(struct wl_listener *listener, void *data) { + struct roots_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 struct roots_layer_popup *popup_create(struct roots_layer_surface *parent, + struct wlr_xdg_popup *wlr_popup) { + struct roots_layer_popup *popup = + calloc(1, sizeof(struct roots_layer_popup)); + if (popup == NULL) { + return NULL; + } + popup->wlr_popup = wlr_popup; + popup->parent = 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); + /* TODO: popups can have popups, see xdg_shell::popup_create */ + + return popup; +} + +static void handle_new_popup(struct wl_listener *listener, void *data) { + struct roots_layer_surface *roots_layer_surface = + wl_container_of(listener, roots_layer_surface, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + popup_create(roots_layer_surface, wlr_popup); +} + void handle_layer_shell_surface(struct wl_listener *listener, void *data) { struct wlr_layer_surface *layer_surface = data; struct roots_desktop *desktop = @@ -338,6 +414,8 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { wl_signal_add(&layer_surface->events.map, &roots_surface->map); roots_surface->unmap.notify = handle_unmap; wl_signal_add(&layer_surface->events.unmap, &roots_surface->unmap); + roots_surface->new_popup.notify = handle_new_popup; + wl_signal_add(&layer_surface->events.new_popup, &roots_surface->new_popup); // TODO: Listen for subsurfaces roots_surface->layer_surface = layer_surface; -- cgit v1.2.3