This updated protocol allows compositors to have a richer set of actions in response to user initiated events, but requires compositors to implement the bindings for what was previously move, resize, and show_window_menu.
Signed-off-by: Adam Goode <[email protected]> --- COPYING | 1 + Makefile.am | 4 + desktop-shell/shell.c | 134 ++-- libweston-desktop/internal.h | 11 +- libweston-desktop/libweston-desktop.c | 40 +- libweston-desktop/libweston-desktop.h | 31 +- libweston-desktop/wl-shell.c | 4 +- libweston-desktop/xdg-shell-v5.c | 7 +- libweston-desktop/xdg-shell-v6.c | 6 +- libweston-desktop/xdg-shell-v7.c | 1238 ++++++++++++++++++++++++++++++++ libweston-desktop/xwayland.c | 27 +- xwayland/window-manager.c | 8 +- xwayland/xwayland-internal-interface.h | 6 +- 13 files changed, 1415 insertions(+), 102 deletions(-) create mode 100644 libweston-desktop/xdg-shell-v7.c diff --git a/COPYING b/COPYING index faefd8f..49da99c 100644 --- a/COPYING +++ b/COPYING @@ -3,6 +3,7 @@ Copyright © 2010-2012 Intel Corporation Copyright © 2010-2011 Benjamin Franzke Copyright © 2011-2012 Collabora, Ltd. Copyright © 2010 Red Hat <[email protected]> +Copyright © 2016 Google Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Makefile.am b/Makefile.am index 2219e3d..a11007d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -127,11 +127,14 @@ libweston_desktop_@LIBWESTON_MAJOR@_la_SOURCES = \ libweston-desktop/seat.c \ libweston-desktop/surface.c \ libweston-desktop/wl-shell.c \ + libweston-desktop/xdg-shell-v7.c \ libweston-desktop/xdg-shell-v6.c \ libweston-desktop/xdg-shell-v5.c \ libweston-desktop/xwayland.c nodist_libweston_desktop_@LIBWESTON_MAJOR@_la_SOURCES = \ + protocol/xdg-shell-unstable-v7-protocol.c \ + protocol/xdg-shell-unstable-v7-server-protocol.h \ protocol/xdg-shell-unstable-v6-protocol.c \ protocol/xdg-shell-unstable-v6-server-protocol.h \ protocol/xdg-shell-unstable-v5-protocol.c \ @@ -139,6 +142,7 @@ nodist_libweston_desktop_@LIBWESTON_MAJOR@_la_SOURCES = \ BUILT_SOURCES += $(nodist_libweston_desktop_@LIBWESTON_MAJOR@_la_SOURCES) +libweston-desktop-@[email protected] libweston-desktop/libweston_desktop_@LIBWESTON_MAJOR@_la-xdg-shell-v7.lo: protocol/xdg-shell-unstable-v7-server-protocol.h libweston-desktop-@[email protected] libweston-desktop/libweston_desktop_@LIBWESTON_MAJOR@_la-xdg-shell-v6.lo: protocol/xdg-shell-unstable-v6-server-protocol.h libweston-desktop-@[email protected] libweston-desktop/libweston_desktop_@LIBWESTON_MAJOR@_la-xdg-shell-v5.lo: protocol/xdg-shell-unstable-v5-server-protocol.h diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 3913f95..6a29483 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -2557,8 +2557,11 @@ set_fullscreen(struct shell_surface *shsurf, bool fullscreen, } static void -desktop_surface_move(struct weston_desktop_surface *desktop_surface, - struct weston_seat *seat, uint32_t serial, void *shell) +desktop_surface_interact_with_decoration(struct weston_desktop_surface *desktop_surface, + struct weston_seat *seat, + uint32_t serial, + enum weston_desktop_surface_decoration_part decoration_part, + void *shell) { struct weston_pointer *pointer = weston_seat_get_pointer(seat); struct weston_touch *touch = weston_seat_get_touch(seat); @@ -2569,49 +2572,91 @@ desktop_surface_move(struct weston_desktop_surface *desktop_surface, struct wl_resource *resource = surface->resource; struct weston_surface *focus; - if (pointer && - pointer->focus && - pointer->button_count > 0 && - pointer->grab_serial == serial) { - focus = weston_surface_get_main_surface(pointer->focus->surface); - if ((focus == surface) && - (surface_move(shsurf, pointer, true) < 0)) - wl_resource_post_no_memory(resource); - } else if (touch && - touch->focus && - touch->grab_serial == serial) { - focus = weston_surface_get_main_surface(touch->focus->surface); - if ((focus == surface) && - (surface_touch_move(shsurf, touch) < 0)) - wl_resource_post_no_memory(resource); - } -} - -static void -desktop_surface_resize(struct weston_desktop_surface *desktop_surface, - struct weston_seat *seat, uint32_t serial, - enum weston_desktop_surface_edge edges, void *shell) -{ - struct weston_pointer *pointer = weston_seat_get_pointer(seat); - struct shell_surface *shsurf = - weston_desktop_surface_get_user_data(desktop_surface); - struct weston_surface *surface = - weston_desktop_surface_get_surface(shsurf->desktop_surface); - struct wl_resource *resource = surface->resource; - struct weston_surface *focus; - - if (!pointer || - pointer->button_count == 0 || - pointer->grab_serial != serial || - pointer->focus == NULL) - return; + /* TODO: implement decoration policies as bindings */ + /* TODO: titlebar double-click: toggle maximize */ + /* TODO: titlebar double-touch: toggle maximize */ + + switch (decoration_part) { + case WESTON_DESKTOP_SURFACE_DECORATION_PART_TITLEBAR: + if (pointer && + pointer->focus && + pointer->button_count > 0 && + pointer->grab_serial == serial) { + focus = weston_surface_get_main_surface(pointer->focus->surface); + if (focus != surface) + break; + + switch (pointer->grab_button) { + case BTN_LEFT: + /* titlebar click: move */ + if (surface_move(shsurf, pointer, true) < 0) + wl_resource_post_no_memory(resource); + break; + case BTN_MIDDLE: + /* titlebar middle-click: lower */ + /* TODO lower */ + break; + default: + break; + } + } else if (touch && + touch->focus && + touch->grab_serial == serial) { + focus = weston_surface_get_main_surface(touch->focus->surface); + if (focus != surface) + break; + + /* titlebar touch: move */ + if (surface_touch_move(shsurf, touch) < 0) + wl_resource_post_no_memory(resource); + } + break; - focus = weston_surface_get_main_surface(pointer->focus->surface); - if (focus != surface) - return; + case WESTON_DESKTOP_SURFACE_DECORATION_PART_TOP: + case WESTON_DESKTOP_SURFACE_DECORATION_PART_BOTTOM: + case WESTON_DESKTOP_SURFACE_DECORATION_PART_LEFT: + case WESTON_DESKTOP_SURFACE_DECORATION_PART_TOP_LEFT: + case WESTON_DESKTOP_SURFACE_DECORATION_PART_BOTTOM_LEFT: + case WESTON_DESKTOP_SURFACE_DECORATION_PART_RIGHT: + case WESTON_DESKTOP_SURFACE_DECORATION_PART_TOP_RIGHT: + case WESTON_DESKTOP_SURFACE_DECORATION_PART_BOTTOM_RIGHT: + if (pointer && + pointer->button_count > 0 && + pointer->focus && + pointer->grab_serial == serial) { + focus = weston_surface_get_main_surface(pointer->focus->surface); + if (focus != surface) + break; + + switch (pointer->grab_button) { + case BTN_LEFT: + /* edge click: resize */ + if (surface_resize(shsurf, pointer, decoration_part) < 0) + wl_resource_post_no_memory(resource); + break; + case BTN_MIDDLE: + /* edge middle-click: lower */ + /* TODO lower */ + break; + default: + break; + } + } else if (touch && + touch->focus && + touch->grab_serial == serial) { + focus = weston_surface_get_main_surface(touch->focus->surface); + if (focus != surface) + break; + + /* edge touch: resize */ + if (surface_resize(shsurf, pointer, decoration_part) < 0) + wl_resource_post_no_memory(resource); + } + break; - if (surface_resize(shsurf, pointer, edges) < 0) - wl_resource_post_no_memory(resource); + default: + break; + } } static void @@ -2788,8 +2833,7 @@ static const struct weston_desktop_api shell_desktop_api = { .surface_added = desktop_surface_added, .surface_removed = desktop_surface_removed, .committed = desktop_surface_committed, - .move = desktop_surface_move, - .resize = desktop_surface_resize, + .interact_with_decoration = desktop_surface_interact_with_decoration, .fullscreen_requested = desktop_surface_fullscreen_requested, .maximized_requested = desktop_surface_maximized_requested, .minimized_requested = desktop_surface_minimized_requested, diff --git a/libweston-desktop/internal.h b/libweston-desktop/internal.h index a9c974b..31a83f4 100644 --- a/libweston-desktop/internal.h +++ b/libweston-desktop/internal.h @@ -67,7 +67,13 @@ void weston_desktop_api_resize(struct weston_desktop *desktop, struct weston_desktop_surface *surface, struct weston_seat *seat, uint32_t serial, - enum weston_desktop_surface_edge edges); + enum weston_desktop_surface_decoration_part decoration_part); +void +weston_desktop_api_interact_with_decoration(struct weston_desktop *desktop, + struct weston_desktop_surface *surface, + struct weston_seat *seat, + uint32_t serial, + enum weston_desktop_surface_decoration_part decoration_part); void weston_desktop_api_fullscreen_requested(struct weston_desktop *desktop, struct weston_desktop_surface *surface, @@ -222,6 +228,9 @@ void weston_desktop_destroy_request(struct wl_client *client, struct wl_resource *resource); struct wl_global * +weston_desktop_xdg_shell_v7_create(struct weston_desktop *desktop, + struct wl_display *display); +struct wl_global * weston_desktop_xdg_shell_v6_create(struct weston_desktop *desktop, struct wl_display *display); struct wl_global * diff --git a/libweston-desktop/libweston-desktop.c b/libweston-desktop/libweston-desktop.c index 0ee1139..cd2c4c8 100644 --- a/libweston-desktop/libweston-desktop.c +++ b/libweston-desktop/libweston-desktop.c @@ -40,6 +40,7 @@ struct weston_desktop { struct weston_compositor *compositor; struct weston_desktop_api api; void *user_data; + struct wl_global *xdg_shell_v7; struct wl_global *xdg_shell_v6; struct wl_global *xdg_shell_v5; struct wl_global *wl_shell; @@ -70,6 +71,13 @@ weston_desktop_create(struct weston_compositor *compositor, MIN(sizeof(struct weston_desktop_api), api->struct_size); memcpy(&desktop->api, api, desktop->api.struct_size); + desktop->xdg_shell_v7 = + weston_desktop_xdg_shell_v7_create(desktop, display); + if (desktop->xdg_shell_v7 == NULL) { + weston_desktop_destroy(desktop); + return NULL; + } + desktop->xdg_shell_v6 = weston_desktop_xdg_shell_v6_create(desktop, display); if (desktop->xdg_shell_v6 == NULL) { @@ -108,6 +116,8 @@ weston_desktop_destroy(struct weston_desktop *desktop) wl_global_destroy(desktop->xdg_shell_v5); if (desktop->xdg_shell_v6 != NULL) wl_global_destroy(desktop->xdg_shell_v6); + if (desktop->xdg_shell_v7 != NULL) + wl_global_destroy(desktop->xdg_shell_v7); free(desktop); } @@ -199,19 +209,37 @@ weston_desktop_api_move(struct weston_desktop *desktop, struct weston_desktop_surface *surface, struct weston_seat *seat, uint32_t serial) { - if (desktop->api.move != NULL) - desktop->api.move(surface, seat, serial, desktop->user_data); + /* Simulate titlebar interaction for v5/v6/wl shell clients */ + if (desktop->api.interact_with_decoration != NULL) + desktop->api.interact_with_decoration(surface, seat, serial, + WESTON_DESKTOP_SURFACE_DECORATION_PART_TITLEBAR, + desktop->user_data); } void weston_desktop_api_resize(struct weston_desktop *desktop, struct weston_desktop_surface *surface, struct weston_seat *seat, uint32_t serial, - enum weston_desktop_surface_edge edges) + enum weston_desktop_surface_decoration_part decoration_part) +{ + /* Simulate edge interaction for v5/v6/wl shell clients */ + if (desktop->api.interact_with_decoration != NULL) + desktop->api.interact_with_decoration(surface, seat, serial, + decoration_part, + desktop->user_data); +} + +void +weston_desktop_api_interact_with_decoration(struct weston_desktop *desktop, + struct weston_desktop_surface *surface, + struct weston_seat *seat, + uint32_t serial, + enum weston_desktop_surface_decoration_part decoration_part) { - if (desktop->api.resize != NULL) - desktop->api.resize(surface, seat, serial, edges, - desktop->user_data); + if (desktop->api.interact_with_decoration != NULL) + desktop->api.interact_with_decoration(surface, seat, serial, + decoration_part, + desktop->user_data); } void diff --git a/libweston-desktop/libweston-desktop.h b/libweston-desktop/libweston-desktop.h index f77ab55..8bb0270 100644 --- a/libweston-desktop/libweston-desktop.h +++ b/libweston-desktop/libweston-desktop.h @@ -32,16 +32,17 @@ extern "C" { #endif -enum weston_desktop_surface_edge { - WESTON_DESKTOP_SURFACE_EDGE_NONE = 0, - WESTON_DESKTOP_SURFACE_EDGE_TOP = 1, - WESTON_DESKTOP_SURFACE_EDGE_BOTTOM = 2, - WESTON_DESKTOP_SURFACE_EDGE_LEFT = 4, - WESTON_DESKTOP_SURFACE_EDGE_TOP_LEFT = 5, - WESTON_DESKTOP_SURFACE_EDGE_BOTTOM_LEFT = 6, - WESTON_DESKTOP_SURFACE_EDGE_RIGHT = 8, - WESTON_DESKTOP_SURFACE_EDGE_TOP_RIGHT = 9, - WESTON_DESKTOP_SURFACE_EDGE_BOTTOM_RIGHT = 10, +enum weston_desktop_surface_decoration_part { + WESTON_DESKTOP_SURFACE_DECORATION_PART_NONE = 0, + WESTON_DESKTOP_SURFACE_DECORATION_PART_TOP = 1, + WESTON_DESKTOP_SURFACE_DECORATION_PART_BOTTOM = 2, + WESTON_DESKTOP_SURFACE_DECORATION_PART_LEFT = 4, + WESTON_DESKTOP_SURFACE_DECORATION_PART_TOP_LEFT = 5, + WESTON_DESKTOP_SURFACE_DECORATION_PART_BOTTOM_LEFT = 6, + WESTON_DESKTOP_SURFACE_DECORATION_PART_RIGHT = 8, + WESTON_DESKTOP_SURFACE_DECORATION_PART_TOP_RIGHT = 9, + WESTON_DESKTOP_SURFACE_DECORATION_PART_BOTTOM_RIGHT = 10, + WESTON_DESKTOP_SURFACE_DECORATION_PART_TITLEBAR = 17, }; struct weston_desktop; @@ -67,11 +68,11 @@ struct weston_desktop_api { void (*set_parent)(struct weston_desktop_surface *surface, struct weston_desktop_surface *parent, void *user_data); - void (*move)(struct weston_desktop_surface *surface, - struct weston_seat *seat, uint32_t serial, void *user_data); - void (*resize)(struct weston_desktop_surface *surface, - struct weston_seat *seat, uint32_t serial, - enum weston_desktop_surface_edge edges, void *user_data); + void (*interact_with_decoration)(struct weston_desktop_surface *surface, + struct weston_seat *seat, + uint32_t serial, + enum weston_desktop_surface_decoration_part decoration_part, + void *user_data); void (*fullscreen_requested)(struct weston_desktop_surface *surface, bool fullscreen, struct weston_output *output, diff --git a/libweston-desktop/wl-shell.c b/libweston-desktop/wl-shell.c index 399139c..76ad988 100644 --- a/libweston-desktop/wl-shell.c +++ b/libweston-desktop/wl-shell.c @@ -235,8 +235,8 @@ weston_desktop_wl_shell_surface_protocol_resize(struct wl_client *wl_client, struct weston_seat *seat = wl_resource_get_user_data(seat_resource); struct weston_desktop_wl_shell_surface *surface = weston_desktop_surface_get_implementation_data(dsurface); - enum weston_desktop_surface_edge surf_edges = - (enum weston_desktop_surface_edge) edges; + enum weston_desktop_surface_decoration_part surf_edges = + (enum weston_desktop_surface_decoration_part) edges; weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, surf_edges); } diff --git a/libweston-desktop/xdg-shell-v5.c b/libweston-desktop/xdg-shell-v5.c index 08cf71e..c31beca 100644 --- a/libweston-desktop/xdg-shell-v5.c +++ b/libweston-desktop/xdg-shell-v5.c @@ -395,11 +395,12 @@ weston_desktop_xdg_surface_protocol_resize(struct wl_client *wl_client, wl_resource_get_user_data(seat_resource); struct weston_desktop_xdg_surface *surface = weston_desktop_surface_get_implementation_data(dsurface); - enum weston_desktop_surface_edge surf_edges = - (enum weston_desktop_surface_edge) edges; + enum weston_desktop_surface_decoration_part decoration_part = + (enum weston_desktop_surface_decoration_part) edges; weston_desktop_xdg_surface_ensure_added(surface); - weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, surf_edges); + weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, + decoration_part); } static void diff --git a/libweston-desktop/xdg-shell-v6.c b/libweston-desktop/xdg-shell-v6.c index 7d0bd8e..a1ab53e 100644 --- a/libweston-desktop/xdg-shell-v6.c +++ b/libweston-desktop/xdg-shell-v6.c @@ -396,8 +396,8 @@ weston_desktop_xdg_toplevel_protocol_resize(struct wl_client *wl_client, wl_resource_get_user_data(seat_resource); struct weston_desktop_xdg_toplevel *toplevel = weston_desktop_surface_get_implementation_data(dsurface); - enum weston_desktop_surface_edge surf_edges = - (enum weston_desktop_surface_edge) edges; + enum weston_desktop_surface_decoration_part decoration_part = + (enum weston_desktop_surface_decoration_part) edges; if (!toplevel->base.configured) { wl_resource_post_error(toplevel->resource, @@ -407,7 +407,7 @@ weston_desktop_xdg_toplevel_protocol_resize(struct wl_client *wl_client, } weston_desktop_api_resize(toplevel->base.desktop, - dsurface, seat, serial, surf_edges); + dsurface, seat, serial, decoration_part); } static void diff --git a/libweston-desktop/xdg-shell-v7.c b/libweston-desktop/xdg-shell-v7.c new file mode 100644 index 0000000..1036275 --- /dev/null +++ b/libweston-desktop/xdg-shell-v7.c @@ -0,0 +1,1238 @@ +/* + * Copyright © 2010-2012 Intel Corporation + * Copyright © 2011-2012 Collabora, Ltd. + * Copyright © 2013 Raspberry Pi Foundation + * Copyright © 2016 Quentin "Sardem FF7" Glidic + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include <stdbool.h> +#include <assert.h> + +#include <wayland-server.h> + +#include "compositor.h" +#include "zalloc.h" +#include "xdg-shell-unstable-v7-server-protocol.h" + +#include "libweston-desktop.h" +#include "internal.h" + +#define WD_XDG_SHELL_PROTOCOL_VERSION 1 + +static const char *weston_desktop_xdg_toplevel_role = "xdg_toplevel"; +static const char *weston_desktop_xdg_popup_role = "xdg_popup"; + +struct weston_desktop_xdg_positioner { + struct weston_desktop *desktop; + struct weston_desktop_client *client; + struct wl_resource *resource; + + struct weston_size size; + struct weston_geometry anchor_rect; + enum zxdg_positioner_v7_anchor anchor; + enum zxdg_positioner_v7_gravity gravity; + enum zxdg_positioner_v7_constraint_adjustment constraint_adjustment; + struct weston_position offset; +}; + +enum weston_desktop_xdg_surface_role { + WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE, + WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL, + WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP, +}; + +struct weston_desktop_xdg_surface { + struct wl_resource *resource; + struct weston_desktop *desktop; + struct weston_surface *surface; + struct weston_desktop_surface *desktop_surface; + bool configured; + struct wl_event_source *configure_idle; + uint32_t configure_serial; + + bool has_next_geometry; + struct weston_geometry next_geometry; + + enum weston_desktop_xdg_surface_role role; +}; + +struct weston_desktop_xdg_toplevel { + struct weston_desktop_xdg_surface base; + + struct wl_resource *resource; + bool added; + struct weston_size requested_size; + struct { + bool maximized; + bool fullscreen; + bool resizing; + bool activated; + } requested_state, next_state, state; + struct weston_size + next_max_size, max_size, + next_min_size, min_size; +}; + +struct weston_desktop_xdg_popup { + struct weston_desktop_xdg_surface base; + + struct wl_resource *resource; + bool committed; + struct weston_desktop_xdg_surface *parent; + struct weston_desktop_seat *seat; + struct weston_geometry geometry; +}; + +#define weston_desktop_surface_role_biggest_size (sizeof(struct weston_desktop_xdg_toplevel)) + + +static struct weston_geometry +weston_desktop_xdg_positioner_get_geometry(struct weston_desktop_xdg_positioner *positioner, + struct weston_desktop_surface *dsurface, + struct weston_desktop_surface *parent) +{ + struct weston_geometry geometry = { + .x = positioner->offset.x, + .y = positioner->offset.y, + .width = positioner->size.width, + .height = positioner->size.height, + }; + + if (positioner->anchor & ZXDG_POSITIONER_V7_ANCHOR_TOP) + geometry.y += positioner->anchor_rect.y; + else if (positioner->anchor & ZXDG_POSITIONER_V7_ANCHOR_BOTTOM) + geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height; + else + geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height / 2; + + if (positioner->anchor & ZXDG_POSITIONER_V7_ANCHOR_LEFT) + geometry.x += positioner->anchor_rect.x; + else if (positioner->anchor & ZXDG_POSITIONER_V7_ANCHOR_RIGHT) + geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width; + else + geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width / 2; + + if (positioner->gravity & ZXDG_POSITIONER_V7_GRAVITY_TOP) + geometry.y -= geometry.height; + else if (positioner->gravity & ZXDG_POSITIONER_V7_GRAVITY_BOTTOM) + geometry.y = geometry.y; + else + geometry.y -= geometry.height / 2; + + if (positioner->gravity & ZXDG_POSITIONER_V7_GRAVITY_LEFT) + geometry.x -= geometry.width; + else if (positioner->gravity & ZXDG_POSITIONER_V7_GRAVITY_RIGHT) + geometry.x = geometry.x; + else + geometry.x -= geometry.width / 2; + + if (positioner->constraint_adjustment == ZXDG_POSITIONER_V7_CONSTRAINT_ADJUSTMENT_NONE) + return geometry; + + /* TODO: add compositor policy configuration and the code here */ + + return geometry; +} + +static void +weston_desktop_xdg_positioner_protocol_set_size(struct wl_client *wl_client, + struct wl_resource *resource, + int32_t width, int32_t height) +{ + struct weston_desktop_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + if (width < 1 || height < 1) { + wl_resource_post_error(resource, + ZXDG_POSITIONER_V7_ERROR_INVALID_INPUT, + "width and height must be positives and non-zero"); + return; + } + + positioner->size.width = width; + positioner->size.height = height; +} + +static void +weston_desktop_xdg_positioner_protocol_set_anchor_rect(struct wl_client *wl_client, + struct wl_resource *resource, + int32_t x, int32_t y, + int32_t width, int32_t height) +{ + struct weston_desktop_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + if (width < 1 || height < 1) { + wl_resource_post_error(resource, + ZXDG_POSITIONER_V7_ERROR_INVALID_INPUT, + "width and height must be positives and non-zero"); + return; + } + + positioner->anchor_rect.x = x; + positioner->anchor_rect.y = y; + positioner->anchor_rect.width = width; + positioner->anchor_rect.height = height; +} + +static void +weston_desktop_xdg_positioner_protocol_set_anchor(struct wl_client *wl_client, + struct wl_resource *resource, + enum zxdg_positioner_v7_anchor anchor) +{ + struct weston_desktop_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + if (((anchor & ZXDG_POSITIONER_V7_ANCHOR_TOP ) && + (anchor & ZXDG_POSITIONER_V7_ANCHOR_BOTTOM)) || + ((anchor & ZXDG_POSITIONER_V7_ANCHOR_LEFT) && + (anchor & ZXDG_POSITIONER_V7_ANCHOR_RIGHT))) { + wl_resource_post_error(resource, + ZXDG_POSITIONER_V7_ERROR_INVALID_INPUT, + "same-axis values are not allowed"); + return; + } + + positioner->anchor = anchor; +} + +static void +weston_desktop_xdg_positioner_protocol_set_gravity(struct wl_client *wl_client, + struct wl_resource *resource, + enum zxdg_positioner_v7_gravity gravity) +{ + struct weston_desktop_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + if (((gravity & ZXDG_POSITIONER_V7_GRAVITY_TOP) && + (gravity & ZXDG_POSITIONER_V7_GRAVITY_BOTTOM)) || + ((gravity & ZXDG_POSITIONER_V7_GRAVITY_LEFT) && + (gravity & ZXDG_POSITIONER_V7_GRAVITY_RIGHT))) { + wl_resource_post_error(resource, + ZXDG_POSITIONER_V7_ERROR_INVALID_INPUT, + "same-axis values are not allowed"); + return; + } + + positioner->gravity = gravity; +} + +static void +weston_desktop_xdg_positioner_protocol_set_constraint_adjustment(struct wl_client *wl_client, + struct wl_resource *resource, + enum zxdg_positioner_v7_constraint_adjustment constraint_adjustment) +{ + struct weston_desktop_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + positioner->constraint_adjustment = constraint_adjustment; +} + +static void +weston_desktop_xdg_positioner_protocol_set_offset(struct wl_client *wl_client, + struct wl_resource *resource, + int32_t x, int32_t y) +{ + struct weston_desktop_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + positioner->offset.x = x; + positioner->offset.y = y; +} + +static void +weston_desktop_xdg_positioner_destroy(struct wl_resource *resource) +{ + struct weston_desktop_xdg_positioner *positioner = + wl_resource_get_user_data(resource); + + free(positioner); +} + +static const struct zxdg_positioner_v7_interface weston_desktop_xdg_positioner_implementation = { + .destroy = weston_desktop_destroy_request, + .set_size = weston_desktop_xdg_positioner_protocol_set_size, + .set_anchor_rect = weston_desktop_xdg_positioner_protocol_set_anchor_rect, + .set_anchor = weston_desktop_xdg_positioner_protocol_set_anchor, + .set_gravity = weston_desktop_xdg_positioner_protocol_set_gravity, + .set_constraint_adjustment = weston_desktop_xdg_positioner_protocol_set_constraint_adjustment, + .set_offset = weston_desktop_xdg_positioner_protocol_set_offset, +}; + +static void +weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface); + +static void +weston_desktop_xdg_toplevel_ensure_added(struct weston_desktop_xdg_toplevel *toplevel) +{ + if (toplevel->added) + return; + + weston_desktop_api_surface_added(toplevel->base.desktop, + toplevel->base.desktop_surface); + weston_desktop_xdg_surface_schedule_configure(&toplevel->base); + toplevel->added = true; +} + +static void +weston_desktop_xdg_toplevel_protocol_set_parent(struct wl_client *wl_client, + struct wl_resource *resource, + struct wl_resource *parent_resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + struct weston_desktop_surface *parent = NULL; + + if (parent_resource != NULL) + parent = wl_resource_get_user_data(parent_resource); + + weston_desktop_xdg_toplevel_ensure_added(toplevel); + weston_desktop_api_set_parent(toplevel->base.desktop, dsurface, parent); +} + +static void +weston_desktop_xdg_toplevel_protocol_set_title(struct wl_client *wl_client, + struct wl_resource *resource, + const char *title) +{ + struct weston_desktop_surface *toplevel = + wl_resource_get_user_data(resource); + + weston_desktop_surface_set_title(toplevel, title); +} + +static void +weston_desktop_xdg_toplevel_protocol_set_app_id(struct wl_client *wl_client, + struct wl_resource *resource, + const char *app_id) +{ + struct weston_desktop_surface *toplevel = + wl_resource_get_user_data(resource); + + weston_desktop_surface_set_app_id(toplevel, app_id); +} + +static void +weston_desktop_xdg_toplevel_protocol_interact_with_decoration(struct wl_client *wl_client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial, + enum zxdg_toplevel_v7_decoration_part decoration_part) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_seat *seat = + wl_resource_get_user_data(seat_resource); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + enum weston_desktop_surface_decoration_part part = + (enum weston_desktop_surface_decoration_part) decoration_part; + + if (!toplevel->base.configured) { + wl_resource_post_error(toplevel->resource, + ZXDG_SURFACE_V7_ERROR_NOT_CONSTRUCTED, + "Surface has not been configured yet"); + return; + } + + weston_desktop_api_interact_with_decoration(toplevel->base.desktop, + dsurface, seat, serial, + part); +} + +static void +weston_desktop_xdg_toplevel_ack_configure(struct weston_desktop_xdg_toplevel *toplevel) +{ + toplevel->next_state = toplevel->requested_state; +} + +static void +weston_desktop_xdg_toplevel_protocol_set_min_size(struct wl_client *wl_client, + struct wl_resource *resource, + int32_t width, int32_t height) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + + toplevel->next_min_size.width = width; + toplevel->next_min_size.height = height; +} + +static void +weston_desktop_xdg_toplevel_protocol_set_max_size(struct wl_client *wl_client, + struct wl_resource *resource, + int32_t width, int32_t height) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + + toplevel->next_max_size.width = width; + toplevel->next_max_size.height = height; +} + +static void +weston_desktop_xdg_toplevel_protocol_set_maximized(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + + weston_desktop_xdg_toplevel_ensure_added(toplevel); + weston_desktop_api_maximized_requested(toplevel->base.desktop, dsurface, true); +} + +static void +weston_desktop_xdg_toplevel_protocol_unset_maximized(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + + weston_desktop_xdg_toplevel_ensure_added(toplevel); + weston_desktop_api_maximized_requested(toplevel->base.desktop, dsurface, false); +} + +static void +weston_desktop_xdg_toplevel_protocol_set_fullscreen(struct wl_client *wl_client, + struct wl_resource *resource, + struct wl_resource *output_resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + struct weston_output *output = NULL; + + if (output_resource != NULL) + output = wl_resource_get_user_data(output_resource); + + weston_desktop_xdg_toplevel_ensure_added(toplevel); + weston_desktop_api_fullscreen_requested(toplevel->base.desktop, dsurface, + true, output); +} + +static void +weston_desktop_xdg_toplevel_protocol_unset_fullscreen(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + + weston_desktop_xdg_toplevel_ensure_added(toplevel); + weston_desktop_api_fullscreen_requested(toplevel->base.desktop, dsurface, + false, NULL); +} + +static void +weston_desktop_xdg_toplevel_protocol_set_minimized(struct wl_client *wl_client, + struct wl_resource *resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + + weston_desktop_xdg_toplevel_ensure_added(toplevel); + weston_desktop_api_minimized_requested(toplevel->base.desktop, dsurface); +} + +static void +weston_desktop_xdg_toplevel_send_configure(struct weston_desktop_xdg_toplevel *toplevel) +{ + uint32_t *s; + struct wl_array states; + + wl_array_init(&states); + if (toplevel->requested_state.maximized) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V7_STATE_MAXIMIZED; + } + if (toplevel->requested_state.fullscreen) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V7_STATE_FULLSCREEN; + } + if (toplevel->requested_state.resizing) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V7_STATE_RESIZING; + } + if (toplevel->requested_state.activated) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V7_STATE_ACTIVATED; + } + + zxdg_toplevel_v7_send_configure(toplevel->resource, + toplevel->requested_size.width, + toplevel->requested_size.height, + &states); + + wl_array_release(&states); +}; + +static void +weston_desktop_xdg_toplevel_set_maximized(struct weston_desktop_surface *dsurface, + void *user_data, bool maximized) +{ + struct weston_desktop_xdg_toplevel *toplevel = user_data; + + if (toplevel->state.maximized == maximized) + return; + + toplevel->requested_state.maximized = maximized; + weston_desktop_xdg_surface_schedule_configure(&toplevel->base); +} + +static void +weston_desktop_xdg_toplevel_set_fullscreen(struct weston_desktop_surface *dsurface, + void *user_data, bool fullscreen) +{ + struct weston_desktop_xdg_toplevel *toplevel = user_data; + + if (toplevel->state.fullscreen == fullscreen) + return; + + toplevel->requested_state.fullscreen = fullscreen; + weston_desktop_xdg_surface_schedule_configure(&toplevel->base); +} + +static void +weston_desktop_xdg_toplevel_set_resizing(struct weston_desktop_surface *dsurface, + void *user_data, bool resizing) +{ + struct weston_desktop_xdg_toplevel *toplevel = user_data; + + if (toplevel->state.resizing == resizing) + return; + + toplevel->requested_state.resizing = resizing; + weston_desktop_xdg_surface_schedule_configure(&toplevel->base); +} + +static void +weston_desktop_xdg_toplevel_set_activated(struct weston_desktop_surface *dsurface, + void *user_data, bool activated) +{ + struct weston_desktop_xdg_toplevel *toplevel = user_data; + + if (toplevel->state.activated == activated) + return; + + toplevel->requested_state.activated = activated; + weston_desktop_xdg_surface_schedule_configure(&toplevel->base); +} + +static void +weston_desktop_xdg_toplevel_set_size(struct weston_desktop_surface *dsurface, + void *user_data, + int32_t width, int32_t height) +{ + struct weston_desktop_xdg_toplevel *toplevel = user_data; + struct weston_surface *wsurface = + weston_desktop_surface_get_surface(toplevel->base.desktop_surface); + + toplevel->requested_size.width = width; + toplevel->requested_size.height = height; + + if ((wsurface->width == width && wsurface->height == height) || + (width == 0 && height == 0)) + return; + + weston_desktop_xdg_surface_schedule_configure(&toplevel->base); +} + +static void +weston_desktop_xdg_toplevel_committed(struct weston_desktop_xdg_toplevel *toplevel, + int32_t sx, int32_t sy) +{ + struct weston_surface *wsurface = + weston_desktop_surface_get_surface(toplevel->base.desktop_surface); + bool reconfigure = false; + + if (!wsurface->buffer_ref.buffer && !toplevel->added) { + weston_desktop_xdg_toplevel_ensure_added(toplevel); + return; + } + if (!wsurface->buffer_ref.buffer) + return; + + if (toplevel->next_state.maximized || toplevel->next_state.fullscreen) + reconfigure = + ( ( toplevel->requested_size.width != wsurface->width ) || + ( toplevel->requested_size.height != wsurface->height ) ); + + if (reconfigure) { + weston_desktop_xdg_surface_schedule_configure(&toplevel->base); + } else { + toplevel->state = toplevel->next_state; + toplevel->min_size = toplevel->next_min_size; + toplevel->max_size = toplevel->next_max_size; + + weston_desktop_api_committed(toplevel->base.desktop, + toplevel->base.desktop_surface, + sx, sy); + } +} + +static void +weston_desktop_xdg_toplevel_close(struct weston_desktop_xdg_toplevel *toplevel) +{ + zxdg_toplevel_v7_send_close(toplevel->resource); +} + +static bool +weston_desktop_xdg_toplevel_get_maximized(struct weston_desktop_surface *dsurface, + void *user_data) +{ + struct weston_desktop_xdg_toplevel *toplevel = user_data; + + return toplevel->state.maximized; +} + +static bool +weston_desktop_xdg_toplevel_get_fullscreen(struct weston_desktop_surface *dsurface, + void *user_data) +{ + struct weston_desktop_xdg_toplevel *toplevel = user_data; + + return toplevel->state.fullscreen; +} + +static bool +weston_desktop_xdg_toplevel_get_resizing(struct weston_desktop_surface *dsurface, + void *user_data) +{ + struct weston_desktop_xdg_toplevel *toplevel = user_data; + + return toplevel->state.resizing; +} + +static bool +weston_desktop_xdg_toplevel_get_activated(struct weston_desktop_surface *dsurface, + void *user_data) +{ + struct weston_desktop_xdg_toplevel *toplevel = user_data; + + return toplevel->state.activated; +} + +static void +weston_desktop_xdg_toplevel_destroy(struct weston_desktop_xdg_toplevel *toplevel) +{ + if (toplevel->added) + weston_desktop_api_surface_removed(toplevel->base.desktop, + toplevel->base.desktop_surface); +} + +static void +weston_desktop_xdg_toplevel_resource_destroy(struct wl_resource *resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + + if (dsurface != NULL) + weston_desktop_surface_resource_destroy(resource); +} + +static const struct zxdg_toplevel_v7_interface weston_desktop_xdg_toplevel_implementation = { + .destroy = weston_desktop_destroy_request, + .set_parent = weston_desktop_xdg_toplevel_protocol_set_parent, + .set_title = weston_desktop_xdg_toplevel_protocol_set_title, + .set_app_id = weston_desktop_xdg_toplevel_protocol_set_app_id, + .interact_with_decoration = weston_desktop_xdg_toplevel_protocol_interact_with_decoration, + .set_min_size = weston_desktop_xdg_toplevel_protocol_set_min_size, + .set_max_size = weston_desktop_xdg_toplevel_protocol_set_max_size, + .set_maximized = weston_desktop_xdg_toplevel_protocol_set_maximized, + .unset_maximized = weston_desktop_xdg_toplevel_protocol_unset_maximized, + .set_fullscreen = weston_desktop_xdg_toplevel_protocol_set_fullscreen, + .unset_fullscreen = weston_desktop_xdg_toplevel_protocol_unset_fullscreen, + .set_minimized = weston_desktop_xdg_toplevel_protocol_set_minimized, +}; + +static void +weston_desktop_xdg_popup_protocol_grab(struct wl_client *wl_client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_popup *popup = + weston_desktop_surface_get_implementation_data(dsurface); + struct weston_seat *wseat = wl_resource_get_user_data(seat_resource); + struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat); + struct weston_desktop_surface *topmost; + bool parent_is_toplevel = + popup->parent->role == WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL; + + if (popup->committed) { + wl_resource_post_error(popup->resource, + ZXDG_POPUP_V7_ERROR_INVALID_GRAB, + "xdg_popup already is mapped"); + return; + } + + topmost = weston_desktop_seat_popup_grab_get_topmost_surface(seat); + if ((topmost == NULL && !parent_is_toplevel) || + (topmost != NULL && topmost != popup->parent->desktop_surface)) { + struct weston_desktop_client *client = + weston_desktop_surface_get_client(dsurface); + struct wl_resource *client_resource = + weston_desktop_client_get_resource(client); + + wl_resource_post_error(client_resource, + ZXDG_SHELL_V7_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was not created on the topmost popup"); + return; + } + + popup->seat = seat; + weston_desktop_surface_popup_grab(popup->base.desktop_surface, + popup->seat, serial); +} + +static void +weston_desktop_xdg_popup_send_configure(struct weston_desktop_xdg_popup *popup) +{ + zxdg_popup_v7_send_configure(popup->resource, + popup->geometry.x, + popup->geometry.y, + popup->geometry.width, + popup->geometry.height); +} + +static void +weston_desktop_xdg_popup_update_position(struct weston_desktop_surface *dsurface, + void *user_data); + +static void +weston_desktop_xdg_popup_committed(struct weston_desktop_xdg_popup *popup) +{ + if (!popup->committed) + weston_desktop_xdg_surface_schedule_configure(&popup->base); + popup->committed = true; + weston_desktop_xdg_popup_update_position(popup->base.desktop_surface, + popup); +} + +static void +weston_desktop_xdg_popup_update_position(struct weston_desktop_surface *dsurface, + void *user_data) +{ +} + +static void +weston_desktop_xdg_popup_close(struct weston_desktop_xdg_popup *popup) +{ + zxdg_popup_v7_send_popup_done(popup->resource); +} + +static void +weston_desktop_xdg_popup_destroy(struct weston_desktop_xdg_popup *popup) +{ + struct weston_desktop_surface *topmost; + struct weston_desktop_client *client = + weston_desktop_surface_get_client(popup->base.desktop_surface); + + if (!weston_desktop_surface_get_grab(popup->base.desktop_surface)) + return; + + topmost = weston_desktop_seat_popup_grab_get_topmost_surface(popup->seat); + if (topmost != popup->base.desktop_surface) { + struct wl_resource *client_resource = + weston_desktop_client_get_resource(client); + + wl_resource_post_error(client_resource, + ZXDG_SHELL_V7_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was destroyed while it was not the topmost popup."); + } + + weston_desktop_surface_popup_ungrab(popup->base.desktop_surface, + popup->seat); +} + +static void +weston_desktop_xdg_popup_resource_destroy(struct wl_resource *resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + + if (dsurface != NULL) + weston_desktop_surface_resource_destroy(resource); +} + +static const struct zxdg_popup_v7_interface weston_desktop_xdg_popup_implementation = { + .destroy = weston_desktop_destroy_request, + .grab = weston_desktop_xdg_popup_protocol_grab, +}; + +static void +weston_desktop_xdg_surface_send_configure(void *user_data) +{ + struct weston_desktop_xdg_surface *surface = user_data; + + surface->configure_idle = NULL; + surface->configure_serial = + wl_display_next_serial(weston_desktop_get_display(surface->desktop)); + + switch (surface->role) { + case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL: + weston_desktop_xdg_toplevel_send_configure((struct weston_desktop_xdg_toplevel *) surface); + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP: + weston_desktop_xdg_popup_send_configure((struct weston_desktop_xdg_popup *) surface); + break; + } + + zxdg_surface_v7_send_configure(surface->resource, surface->configure_serial); +} + +static void +weston_desktop_xdg_surface_schedule_configure(struct weston_desktop_xdg_surface *surface) +{ + struct wl_display *display = weston_desktop_get_display(surface->desktop); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + + if (surface->configure_idle != NULL) + return; + surface->configure_idle = + wl_event_loop_add_idle(loop, + weston_desktop_xdg_surface_send_configure, + surface); +} + +static void +weston_desktop_xdg_surface_protocol_get_toplevel(struct wl_client *wl_client, + struct wl_resource *resource, + uint32_t id) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_surface *wsurface = + weston_desktop_surface_get_surface(dsurface); + struct weston_desktop_xdg_toplevel *toplevel = + weston_desktop_surface_get_implementation_data(dsurface); + + if (weston_surface_set_role(wsurface, weston_desktop_xdg_toplevel_role, + resource, ZXDG_SHELL_V7_ERROR_ROLE) < 0) + return; + + toplevel->resource = + weston_desktop_surface_add_resource(toplevel->base.desktop_surface, + &zxdg_toplevel_v7_interface, + &weston_desktop_xdg_toplevel_implementation, + id, weston_desktop_xdg_toplevel_resource_destroy); + if (toplevel->resource == NULL) + return; + + toplevel->base.role = WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL; +} + +static void +weston_desktop_xdg_surface_protocol_get_popup(struct wl_client *wl_client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *parent_resource, + struct wl_resource *positioner_resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_surface *wsurface = + weston_desktop_surface_get_surface(dsurface); + struct weston_desktop_xdg_popup *popup = + weston_desktop_surface_get_implementation_data(dsurface); + struct weston_desktop_surface *parent_surface = + wl_resource_get_user_data(parent_resource); + struct weston_desktop_xdg_surface *parent = + weston_desktop_surface_get_implementation_data(parent_surface); + struct weston_desktop_xdg_positioner *positioner = + wl_resource_get_user_data(positioner_resource); + + /* Checking whether the size and anchor rect both have a positive size + * is enough to verify both have been correctly set */ + if (positioner->size.width == 0 || positioner->anchor_rect.width == 0) { + wl_resource_post_error(resource, + ZXDG_SHELL_V7_ERROR_INVALID_POSITIONER, + "positioner object is not complete"); + return; + } + + if (weston_surface_set_role(wsurface, weston_desktop_xdg_popup_role, + resource, ZXDG_SHELL_V7_ERROR_ROLE) < 0) + return; + + popup->resource = + weston_desktop_surface_add_resource(popup->base.desktop_surface, + &zxdg_popup_v7_interface, + &weston_desktop_xdg_popup_implementation, + id, weston_desktop_xdg_popup_resource_destroy); + if (popup->resource == NULL) + return; + + popup->base.role = WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP; + popup->parent = parent; + + popup->geometry = + weston_desktop_xdg_positioner_get_geometry(positioner, + dsurface, + parent_surface); + + weston_desktop_surface_set_relative_to(popup->base.desktop_surface, + parent_surface, + popup->geometry.x, + popup->geometry.y, + true); +} + +static bool +weston_desktop_xdg_surface_check_role(struct weston_desktop_xdg_surface *surface) +{ + struct weston_surface *wsurface = + weston_desktop_surface_get_surface(surface->desktop_surface); + const char *role; + + role = weston_surface_get_role(wsurface); + if (role != NULL && + (role == weston_desktop_xdg_toplevel_role || + role == weston_desktop_xdg_popup_role)) + return true; + + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V7_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + return false; +} + +static void +weston_desktop_xdg_surface_protocol_set_window_geometry(struct wl_client *wl_client, + struct wl_resource *resource, + int32_t x, int32_t y, + int32_t width, int32_t height) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_surface *surface = + weston_desktop_surface_get_implementation_data(dsurface); + + if (!weston_desktop_xdg_surface_check_role(surface)) + return; + + surface->has_next_geometry = true; + surface->next_geometry.x = x; + surface->next_geometry.y = y; + surface->next_geometry.width = width; + surface->next_geometry.height = height; +} + +static void +weston_desktop_xdg_surface_protocol_ack_configure(struct wl_client *wl_client, + struct wl_resource *resource, + uint32_t serial) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_surface *surface = + weston_desktop_surface_get_implementation_data(dsurface); + + if (!weston_desktop_xdg_surface_check_role(surface)) + return; + + if (surface->configure_serial != serial) + return; + + surface->configured = true; + + switch (surface->role) { + case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL: + weston_desktop_xdg_toplevel_ack_configure((struct weston_desktop_xdg_toplevel *) surface); + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP: + break; + } +} + +static void +weston_desktop_xdg_surface_ping(struct weston_desktop_surface *dsurface, + uint32_t serial, void *user_data) +{ + struct weston_desktop_client *client = + weston_desktop_surface_get_client(dsurface); + + zxdg_shell_v7_send_ping(weston_desktop_client_get_resource(client), + serial); +} + +static void +weston_desktop_xdg_surface_committed(struct weston_desktop_surface *dsurface, + void *user_data, + int32_t sx, int32_t sy) +{ + struct weston_desktop_xdg_surface *surface = user_data; + struct weston_surface *wsurface = + weston_desktop_surface_get_surface (dsurface); + + if (wsurface->buffer_ref.buffer && !surface->configured) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V7_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface has never been configured"); + return; + } + + if (surface->has_next_geometry) { + surface->has_next_geometry = false; + weston_desktop_surface_set_geometry(surface->desktop_surface, + surface->next_geometry); + } + + switch (surface->role) { + case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE: + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V7_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL: + weston_desktop_xdg_toplevel_committed((struct weston_desktop_xdg_toplevel *) surface, sx, sy); + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP: + weston_desktop_xdg_popup_committed((struct weston_desktop_xdg_popup *) surface); + break; + } +} + +static void +weston_desktop_xdg_surface_close(struct weston_desktop_surface *dsurface, + void *user_data) +{ + struct weston_desktop_xdg_surface *surface = user_data; + + switch (surface->role) { + case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE: + assert(0 && "not reached"); + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL: + weston_desktop_xdg_toplevel_close((struct weston_desktop_xdg_toplevel *) surface); + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP: + weston_desktop_xdg_popup_close((struct weston_desktop_xdg_popup *) surface); + break; + } +} + +static void +weston_desktop_xdg_surface_destroy(struct weston_desktop_surface *dsurface, + void *user_data) +{ + struct weston_desktop_xdg_surface *surface = user_data; + + switch (surface->role) { + case WESTON_DESKTOP_XDG_SURFACE_ROLE_NONE: + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_TOPLEVEL: + weston_desktop_xdg_toplevel_destroy((struct weston_desktop_xdg_toplevel *) surface); + break; + case WESTON_DESKTOP_XDG_SURFACE_ROLE_POPUP: + weston_desktop_xdg_popup_destroy((struct weston_desktop_xdg_popup *) surface); + break; + } + + if (surface->configure_idle != NULL) + wl_event_source_remove(surface->configure_idle); + + free(surface); +} + +static const struct zxdg_surface_v7_interface weston_desktop_xdg_surface_implementation = { + .destroy = weston_desktop_destroy_request, + .get_toplevel = weston_desktop_xdg_surface_protocol_get_toplevel, + .get_popup = weston_desktop_xdg_surface_protocol_get_popup, + .set_window_geometry = weston_desktop_xdg_surface_protocol_set_window_geometry, + .ack_configure = weston_desktop_xdg_surface_protocol_ack_configure, +}; + +static const struct weston_desktop_surface_implementation weston_desktop_xdg_surface_internal_implementation = { + /* These are used for toplevel only */ + .set_maximized = weston_desktop_xdg_toplevel_set_maximized, + .set_fullscreen = weston_desktop_xdg_toplevel_set_fullscreen, + .set_resizing = weston_desktop_xdg_toplevel_set_resizing, + .set_activated = weston_desktop_xdg_toplevel_set_activated, + .set_size = weston_desktop_xdg_toplevel_set_size, + + .get_maximized = weston_desktop_xdg_toplevel_get_maximized, + .get_fullscreen = weston_desktop_xdg_toplevel_get_fullscreen, + .get_resizing = weston_desktop_xdg_toplevel_get_resizing, + .get_activated = weston_desktop_xdg_toplevel_get_activated, + + /* These are used for popup only */ + .update_position = weston_desktop_xdg_popup_update_position, + + /* Common API */ + .committed = weston_desktop_xdg_surface_committed, + .ping = weston_desktop_xdg_surface_ping, + .close = weston_desktop_xdg_surface_close, + + .destroy = weston_desktop_xdg_surface_destroy, +}; + +static void +weston_desktop_xdg_shell_protocol_create_positioner(struct wl_client *wl_client, + struct wl_resource *resource, + uint32_t id) +{ + struct weston_desktop_client *client = + wl_resource_get_user_data(resource); + struct weston_desktop_xdg_positioner *positioner; + + positioner = zalloc(sizeof(struct weston_desktop_xdg_positioner)); + if (positioner == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + positioner->client = client; + positioner->desktop = weston_desktop_client_get_desktop(positioner->client); + + positioner->resource = + wl_resource_create(wl_client, + &zxdg_positioner_v7_interface, + wl_resource_get_version(resource), id); + if (positioner->resource == NULL) { + wl_client_post_no_memory(wl_client); + free(positioner); + return; + } + wl_resource_set_implementation(positioner->resource, + &weston_desktop_xdg_positioner_implementation, + positioner, weston_desktop_xdg_positioner_destroy); +} + +static void +weston_desktop_xdg_surface_resource_destroy(struct wl_resource *resource) +{ + struct weston_desktop_surface *dsurface = + wl_resource_get_user_data(resource); + + if (dsurface != NULL) + weston_desktop_surface_resource_destroy(resource); +} + +static void +weston_desktop_xdg_shell_protocol_get_xdg_surface(struct wl_client *wl_client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource) +{ + struct weston_desktop_client *client = + wl_resource_get_user_data(resource); + struct weston_surface *wsurface = + wl_resource_get_user_data(surface_resource); + struct weston_desktop_xdg_surface *surface; + + surface = zalloc(weston_desktop_surface_role_biggest_size); + if (surface == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + surface->desktop = weston_desktop_client_get_desktop(client); + surface->surface = wsurface; + + surface->desktop_surface = + weston_desktop_surface_create(surface->desktop, client, + surface->surface, + &weston_desktop_xdg_surface_internal_implementation, + surface); + if (surface->desktop_surface == NULL) { + free(surface); + return; + } + + surface->resource = + weston_desktop_surface_add_resource(surface->desktop_surface, + &zxdg_surface_v7_interface, + &weston_desktop_xdg_surface_implementation, + id, weston_desktop_xdg_surface_resource_destroy); + if (surface->resource == NULL) + return; + + if (wsurface->buffer_ref.buffer != NULL) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V7_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface must not have a buffer at creation"); + return; + } +} + +static void +weston_desktop_xdg_shell_protocol_pong(struct wl_client *wl_client, + struct wl_resource *resource, + uint32_t serial) +{ + struct weston_desktop_client *client = + wl_resource_get_user_data(resource); + + weston_desktop_client_pong(client, serial); +} + +static const struct zxdg_shell_v7_interface weston_desktop_xdg_shell_implementation = { + .destroy = weston_desktop_destroy_request, + .create_positioner = weston_desktop_xdg_shell_protocol_create_positioner, + .get_xdg_surface = weston_desktop_xdg_shell_protocol_get_xdg_surface, + .pong = weston_desktop_xdg_shell_protocol_pong, +}; + +static void +weston_desktop_xdg_shell_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) +{ + struct weston_desktop *desktop = data; + + weston_desktop_client_create(desktop, client, NULL, + &zxdg_shell_v7_interface, + &weston_desktop_xdg_shell_implementation, + version, id); +} + +struct wl_global * +weston_desktop_xdg_shell_v7_create(struct weston_desktop *desktop, struct wl_display *display) +{ + return wl_global_create(display, &zxdg_shell_v7_interface, + WD_XDG_SHELL_PROTOCOL_VERSION, desktop, + weston_desktop_xdg_shell_bind); +} diff --git a/libweston-desktop/xwayland.c b/libweston-desktop/xwayland.c index 6b90c14..cc18bca 100644 --- a/libweston-desktop/xwayland.c +++ b/libweston-desktop/xwayland.c @@ -298,27 +298,17 @@ set_xwayland(struct weston_desktop_xwayland_surface *surface, int x, int y) } static int -move(struct weston_desktop_xwayland_surface *surface, - struct weston_pointer *pointer) +interact_with_decoration(struct weston_desktop_xwayland_surface *surface, + struct weston_pointer *pointer, uint32_t edges) { if (surface->state == TOPLEVEL || surface->state == MAXIMIZED || surface->state == FULLSCREEN) - weston_desktop_api_move(surface->desktop, surface->surface, - pointer->seat, pointer->grab_serial); - return 0; -} - -static int -resize(struct weston_desktop_xwayland_surface *surface, - struct weston_pointer *pointer, uint32_t edges) -{ - if (surface->state == TOPLEVEL || - surface->state == MAXIMIZED || - surface->state == FULLSCREEN) - weston_desktop_api_resize(surface->desktop, surface->surface, - pointer->seat, pointer->grab_serial, - edges); + weston_desktop_api_interact_with_decoration(surface->desktop, + surface->surface, + pointer->seat, + pointer->grab_serial, + edges); return 0; } @@ -361,8 +351,7 @@ static const struct weston_desktop_xwayland_interface weston_desktop_xwayland_in .set_transient = set_transient, .set_fullscreen = set_fullscreen, .set_xwayland = set_xwayland, - .move = move, - .resize = resize, + .interact_with_decoration = interact_with_decoration, .set_title = set_title, .set_window_geometry = set_window_geometry, .set_maximized = set_maximized, diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 56d65af..628109f 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -1368,7 +1368,7 @@ weston_wm_window_handle_moveresize(struct weston_wm_window *window, detail = client_message->data.data32[2]; switch (detail) { case _NET_WM_MOVERESIZE_MOVE: - xwayland_interface->move(window->shsurf, pointer); + xwayland_interface->interact_with_decoration(window->shsurf, pointer, THEME_LOCATION_TITLEBAR); break; case _NET_WM_MOVERESIZE_SIZE_TOPLEFT: case _NET_WM_MOVERESIZE_SIZE_TOP: @@ -1378,7 +1378,7 @@ weston_wm_window_handle_moveresize(struct weston_wm_window *window, case _NET_WM_MOVERESIZE_SIZE_BOTTOM: case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: case _NET_WM_MOVERESIZE_SIZE_LEFT: - xwayland_interface->resize(window->shsurf, pointer, map[detail]); + xwayland_interface->interact_with_decoration(window->shsurf, pointer, map[detail]); break; case _NET_WM_MOVERESIZE_CANCEL: break; @@ -1799,13 +1799,13 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) if (frame_status(window->frame) & FRAME_STATUS_MOVE) { if (pointer) - xwayland_interface->move(window->shsurf, pointer); + xwayland_interface->interact_with_decoration(window->shsurf, pointer, THEME_LOCATION_TITLEBAR); frame_status_clear(window->frame, FRAME_STATUS_MOVE); } if (frame_status(window->frame) & FRAME_STATUS_RESIZE) { if (pointer) - xwayland_interface->resize(window->shsurf, pointer, location); + xwayland_interface->interact_with_decoration(window->shsurf, pointer, location); frame_status_clear(window->frame, FRAME_STATUS_RESIZE); } diff --git a/xwayland/xwayland-internal-interface.h b/xwayland/xwayland-internal-interface.h index e771730..96bea8d 100644 --- a/xwayland/xwayland-internal-interface.h +++ b/xwayland/xwayland-internal-interface.h @@ -46,10 +46,8 @@ struct weston_desktop_xwayland_interface { struct weston_output *output); void (*set_xwayland)(struct weston_desktop_xwayland_surface *shsurf, int x, int y); - int (*move)(struct weston_desktop_xwayland_surface *shsurf, - struct weston_pointer *pointer); - int (*resize)(struct weston_desktop_xwayland_surface *shsurf, - struct weston_pointer *pointer, uint32_t edges); + int (*interact_with_decoration)(struct weston_desktop_xwayland_surface *shsurf, + struct weston_pointer *pointer, uint32_t edges); void (*set_title)(struct weston_desktop_xwayland_surface *shsurf, const char *title); void (*set_window_geometry)(struct weston_desktop_xwayland_surface *shsurf, -- 2.8.0.rc3.226.g39d4020 _______________________________________________ wayland-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/wayland-devel
