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 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 9 deletions(-) (limited to 'examples') 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; -- 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 'examples') 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 'examples') 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 941f88ce2367164bb78769ad832d8a748d7e9aca Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 14 Apr 2018 22:21:05 -0400 Subject: Fix popup positioning & double popups --- examples/layer-shell.c | 3 +-- types/wlr_layer_shell.c | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 56fa28f7..1824c50c 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -175,8 +175,7 @@ static void create_popup() { xdg_positioner_set_size(xdg_positioner, 256, 256); 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_anchor(xdg_positioner, XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT); popup = xdg_surface_get_popup(xdg_surface, NULL, xdg_positioner); assert(popup); diff --git a/types/wlr_layer_shell.c b/types/wlr_layer_shell.c index 9a18bebd..c61556bf 100644 --- a/types/wlr_layer_shell.c +++ b/types/wlr_layer_shell.c @@ -465,6 +465,33 @@ static void layer_surface_iterator(struct wlr_surface *surface, iter_data->user_data); } +static void xdg_surface_for_each_surface(struct wlr_xdg_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; + wlr_xdg_surface_popup_get_position(popup, &popup_sx, &popup_sy); + + xdg_surface_for_each_surface(popup, + x + popup_sx, + y + popup_sy, + iterator, 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 = { @@ -483,13 +510,11 @@ static void layer_surface_for_each_surface(struct wlr_layer_surface *surface, } 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); + popup_sx = popup->popup->geometry.x - popup->geometry.x; + popup_sy = popup->popup->geometry.y - popup->geometry.y; - wlr_xdg_surface_for_each_surface(popup, layer_surface_iterator, &data); + xdg_surface_for_each_surface(popup, + popup_sx, popup_sy, iterator, user_data); } } -- cgit v1.2.3 From d1e82a8ede200862453e50cb77bf7cd6e1e73d33 Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Thu, 19 Apr 2018 12:26:18 +0200 Subject: examples: Drop unused variable --- examples/layer-shell.c | 1 - 1 file changed, 1 deletion(-) (limited to 'examples') diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 1824c50c..718fbe0a 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -39,7 +39,6 @@ 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; -- cgit v1.2.3 From 421652a450eca9910aec0491760a0ce7ff69ee24 Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Fri, 20 Apr 2018 15:05:48 +0200 Subject: examples: Animate popup in layer-shell --- examples/layer-shell.c | 74 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 17 deletions(-) (limited to 'examples') diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 718fbe0a..115b72cb 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -40,6 +40,12 @@ struct wl_callback *frame_callback; static uint32_t output = UINT32_MAX; struct xdg_popup *popup; +struct wl_surface *popup_wl_surface; +struct wl_egl_window *popup_egl_window; +static uint32_t popup_width = 256, popup_height = 256; +struct wlr_egl_surface *popup_egl_surface; +struct wl_callback *popup_frame_callback; +float popup_alpha = 1.0; static uint32_t layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; static uint32_t anchor = 0; @@ -64,6 +70,7 @@ static struct { } demo; static void draw(void); +static void draw_popup(void); static void surface_frame_callback( void *data, struct wl_callback *cb, uint32_t time) { @@ -76,9 +83,19 @@ static struct wl_callback_listener frame_listener = { .done = surface_frame_callback }; +static void popup_surface_frame_callback( + void *data, struct wl_callback *cb, uint32_t time) { + wl_callback_destroy(cb); + popup_frame_callback = NULL; + draw_popup(); +} + +static struct wl_callback_listener popup_frame_listener = { + .done = popup_surface_frame_callback +}; + static void draw(void) { eglMakeCurrent(egl.display, egl_surface, egl_surface, egl.context); - struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -132,10 +149,28 @@ static void draw(void) { demo.last_frame = ts; } +static void draw_popup() { + static float alpha_mod = -0.01; + + eglMakeCurrent(egl.display, popup_egl_surface, popup_egl_surface, egl.context); + glViewport(0, 0, popup_width, popup_height); + glClearColor(0.5f, 0.5f, 0.5f, popup_alpha); + popup_alpha += alpha_mod; + if (popup_alpha < 0.01 || popup_alpha >= 1.0f) { + alpha_mod *= -1.0; + } + glClear(GL_COLOR_BUFFER_BIT); + + popup_frame_callback = wl_surface_frame(popup_wl_surface); + assert(popup_frame_callback); + wl_callback_add_listener(popup_frame_callback, &popup_frame_listener, NULL); + eglSwapBuffers(egl.display, popup_egl_surface); + wl_surface_commit(popup_wl_surface); +} + 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 = { @@ -146,10 +181,17 @@ static void xdg_popup_configure(void *data, struct xdg_popup *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height) { wlr_log(L_DEBUG, "Popup configured %dx%d@%d,%d", width, height, x, y); + popup_width = width; + popup_height = height; + if (popup_egl_window) { + wl_egl_window_resize(popup_egl_window, width, height, 0, 0); + } } static void xdg_popup_done(void *data, struct xdg_popup *xdg_popup) { - // We leak the surface, but who cares + eglDestroySurface(egl.display, popup_egl_surface); + wl_egl_window_destroy(popup_egl_window); + wl_surface_destroy(popup_wl_surface); xdg_popup_destroy(popup); popup = NULL; } @@ -171,7 +213,7 @@ static void create_popup() { xdg_wm_base_create_positioner(xdg_wm_base); assert(xdg_surface && xdg_positioner); - xdg_positioner_set_size(xdg_positioner, 256, 256); + xdg_positioner_set_size(xdg_positioner, popup_width, popup_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_BOTTOM_RIGHT); @@ -189,17 +231,12 @@ static void create_popup() { 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); - 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); + popup_wl_surface = surface; + popup_egl_window = wl_egl_window_create(surface, popup_width, popup_height); + assert(popup_egl_window); + popup_egl_surface = wlr_egl_create_surface(&egl, popup_egl_window); + assert(popup_egl_surface); + draw_popup(); } static void layer_surface_configure(void *data, @@ -252,12 +289,15 @@ static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, 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++; } } else { - buttons--; + if (button != BTN_RIGHT) { + buttons--; + } } } -- cgit v1.2.3 From 5209c797026cc5c97d2abc796b70d43ceaaac519 Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Mon, 23 Apr 2018 09:53:46 +0200 Subject: examples: Handle input entering popup in layer-shell Change the cursor when entering the popup and make mouse buttons change the red component of the square. This makes sure we can handle input correctly. --- examples/layer-shell.c | 61 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 17 deletions(-) (limited to 'examples') diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 115b72cb..721fd69e 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -45,7 +45,7 @@ struct wl_egl_window *popup_egl_window; static uint32_t popup_width = 256, popup_height = 256; struct wlr_egl_surface *popup_egl_surface; struct wl_callback *popup_frame_callback; -float popup_alpha = 1.0; +float popup_alpha = 1.0, popup_red = 0.5f; static uint32_t layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; static uint32_t anchor = 0; @@ -59,9 +59,9 @@ static double frame = 0; static int cur_x = -1, cur_y = -1; static int buttons = 0; -struct wl_cursor_theme *cursor_theme; struct wl_cursor_image *cursor_image; -struct wl_surface *cursor_surface; +struct wl_cursor_image *popup_cursor_image; +struct wl_surface *cursor_surface, *input_surface; static struct { struct timespec last_frame; @@ -154,7 +154,7 @@ static void draw_popup() { eglMakeCurrent(egl.display, popup_egl_surface, popup_egl_surface, egl.context); glViewport(0, 0, popup_width, popup_height); - glClearColor(0.5f, 0.5f, 0.5f, popup_alpha); + glClearColor(popup_red, 0.5f, 0.5f, popup_alpha); popup_alpha += alpha_mod; if (popup_alpha < 0.01 || popup_alpha >= 1.0f) { alpha_mod *= -1.0; @@ -267,11 +267,20 @@ struct zwlr_layer_surface_v1_listener layer_surface_listener = { static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + struct wl_cursor_image *image; + if (surface == popup_wl_surface) { + image = popup_cursor_image; + } else { + image = cursor_image; + } wl_surface_attach(cursor_surface, - wl_cursor_image_get_buffer(cursor_image), 0, 0); - wl_pointer_set_cursor(wl_pointer, serial, cursor_surface, - cursor_image->hotspot_x, cursor_image->hotspot_y); + wl_cursor_image_get_buffer(image), 0, 0); + wl_surface_damage(cursor_surface, 1, 0, + image->width, image->height); wl_surface_commit(cursor_surface); + wl_pointer_set_cursor(wl_pointer, serial, cursor_surface, + image->hotspot_x, image->hotspot_y); + input_surface = surface; } static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, @@ -288,16 +297,28 @@ static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, 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) { - if (button == BTN_RIGHT) { - create_popup(); + if (input_surface == wl_surface) { + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (button == BTN_RIGHT) { + create_popup(); + } else { + buttons++; + } } else { - buttons++; + if (button != BTN_RIGHT) { + buttons--; + } } - } else { - if (button != BTN_RIGHT) { - buttons--; + } else if (input_surface == popup_wl_surface) { + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (button == BTN_LEFT && popup_red <= 0.9f) { + popup_red += 0.1; + } else if (button == BTN_RIGHT && popup_red >= 0.1f) { + popup_red -= 0.1; + } } + } else { + assert(false && "Unknown surface"); } } @@ -557,12 +578,18 @@ int main(int argc, char **argv) { return 1; } - cursor_theme = wl_cursor_theme_load(NULL, 16, shm); + struct wl_cursor_theme *cursor_theme = + wl_cursor_theme_load(NULL, 16, shm); assert(cursor_theme); - struct wl_cursor *cursor; - cursor = wl_cursor_theme_get_cursor(cursor_theme, "crosshair"); + struct wl_cursor *cursor = + wl_cursor_theme_get_cursor(cursor_theme, "crosshair"); assert(cursor); cursor_image = cursor->images[0]; + + cursor = wl_cursor_theme_get_cursor(cursor_theme, "tcross"); + assert(cursor); + popup_cursor_image = cursor->images[0]; + cursor_surface = wl_compositor_create_surface(compositor); assert(cursor_surface); -- cgit v1.2.3 From 32e043f996d00428731e9d97f8e45180574681b1 Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Mon, 23 Apr 2018 09:53:46 +0200 Subject: examples: Allow to close the popup So we can the xdg_popup_destroy path. --- examples/layer-shell.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/layer-shell.c b/examples/layer-shell.c index 721fd69e..0e1d61ca 100644 --- a/examples/layer-shell.c +++ b/examples/layer-shell.c @@ -188,12 +188,20 @@ static void xdg_popup_configure(void *data, struct xdg_popup *xdg_popup, } } -static void xdg_popup_done(void *data, struct xdg_popup *xdg_popup) { +static void popup_destroy() +{ eglDestroySurface(egl.display, popup_egl_surface); wl_egl_window_destroy(popup_egl_window); - wl_surface_destroy(popup_wl_surface); xdg_popup_destroy(popup); + wl_surface_destroy(popup_wl_surface); + popup_wl_surface = NULL; popup = NULL; + popup_egl_window = NULL; +} + +static void xdg_popup_done(void *data, struct xdg_popup *xdg_popup) { + wlr_log(L_DEBUG, "Popup done"); + popup_destroy(); } static const struct xdg_popup_listener xdg_popup_listener = { @@ -300,7 +308,11 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, if (input_surface == wl_surface) { if (state == WL_POINTER_BUTTON_STATE_PRESSED) { if (button == BTN_RIGHT) { - create_popup(); + if (popup_wl_surface) { + popup_destroy(); + } else { + create_popup(); + } } else { buttons++; } -- cgit v1.2.3