From d714a94d97af8b34721236bb8ca6f0e3fd6dc1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 22 Dec 2017 16:37:44 +0800 Subject: [PATCH] wayland: Add support for stable xdg-shell This commit adds support for xdg_shell (the stable version). This was done by first copying the old xdg-shell unstable v6 implementation into a separate .c .h file pair (including various symbol renaming) then porting the old xdg-shell unstable v6 implementation to the new stable version. https://gitlab.gnome.org/GNOME/mutter/merge_requests/5 https://bugzilla.gnome.org/show_bug.cgi?id=791938 --- .gitignore | 2 + src/Makefile.am | 6 +- src/wayland/meta-wayland-legacy-xdg-shell.c | 1982 +++++++++++++++++++ src/wayland/meta-wayland-legacy-xdg-shell.h | 53 + src/wayland/meta-wayland-surface.c | 17 + src/wayland/meta-wayland-surface.h | 4 + src/wayland/meta-wayland-versions.h | 3 +- src/wayland/meta-wayland-xdg-foreign.c | 9 +- src/wayland/meta-wayland-xdg-shell.c | 498 +++-- src/wayland/meta-wayland-xdg-shell.h | 1 + 10 files changed, 2397 insertions(+), 178 deletions(-) create mode 100644 src/wayland/meta-wayland-legacy-xdg-shell.c create mode 100644 src/wayland/meta-wayland-legacy-xdg-shell.h diff --git a/.gitignore b/.gitignore index 39fe0bb4e..92ee75c56 100644 --- a/.gitignore +++ b/.gitignore @@ -98,6 +98,8 @@ src/keyboard-shortcuts-inhibit-unstable-v*-protocol.c src/keyboard-shortcuts-inhibit-unstable-v*-server-protocol.h src/linux-dmabuf-unstable-v*-protocol.c src/linux-dmabuf-unstable-v*-server-protocol.h +src/xdg-shell-protocol.c +src/xdg-shell-server-protocol.h src/meta/meta-version.h src/libmutter-*.pc doc/reference/*.args diff --git a/src/Makefile.am b/src/Makefile.am index 617aada1e..3b50bf589 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -68,6 +68,8 @@ mutter_built_sources += \ gtk-shell-server-protocol.h \ gtk-primary-selection-protocol.c \ gtk-primary-selection-server-protocol.h \ + xdg-shell-protocol.c \ + xdg-shell-server-protocol.h \ xdg-shell-unstable-v6-protocol.c \ xdg-shell-unstable-v6-server-protocol.h \ relative-pointer-unstable-v1-protocol.c \ @@ -454,6 +456,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES += \ wayland/meta-window-xwayland.h \ wayland/meta-wayland-xdg-shell.c \ wayland/meta-wayland-xdg-shell.h \ + wayland/meta-wayland-legacy-xdg-shell.c \ + wayland/meta-wayland-legacy-xdg-shell.h \ wayland/meta-wayland-wl-shell.c \ wayland/meta-wayland-wl-shell.h \ wayland/meta-wayland-gtk-shell.c \ @@ -742,7 +746,7 @@ backends/native/meta-default-modes.h: backends/native/gen-default-modes.py Makef .SECONDEXPANSION: define protostability -$(shell echo $1 | sed 's/.*\(\\|\\).*/\1/') +$(if $(findstring unstable,$1),unstable,stable) endef define protoname diff --git a/src/wayland/meta-wayland-legacy-xdg-shell.c b/src/wayland/meta-wayland-legacy-xdg-shell.c new file mode 100644 index 000000000..c43bcff3e --- /dev/null +++ b/src/wayland/meta-wayland-legacy-xdg-shell.c @@ -0,0 +1,1982 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2012-2013 Intel Corporation + * Copyright (C) 2013-2015 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#include "config.h" + +#include "wayland/meta-wayland-legacy-xdg-shell.h" + +#include "backends/meta-logical-monitor.h" +#include "core/window-private.h" +#include "wayland/meta-wayland.h" +#include "wayland/meta-wayland-outputs.h" +#include "wayland/meta-wayland-popup.h" +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-seat.h" +#include "wayland/meta-wayland-shell-surface.h" +#include "wayland/meta-wayland-surface.h" +#include "wayland/meta-wayland-versions.h" +#include "wayland/meta-window-wayland.h" + +#include "xdg-shell-unstable-v6-server-protocol.h" + +enum +{ + ZXDG_SURFACE_V6_PROP_0, + + ZXDG_SURFACE_V6_PROP_SHELL_CLIENT, + ZXDG_SURFACE_V6_PROP_RESOURCE, +}; + +typedef struct _MetaWaylandZxdgShellV6Client +{ + struct wl_resource *resource; + GList *surfaces; + GList *surface_constructors; +} MetaWaylandZxdgShellV6Client; + +typedef struct _MetaWaylandZxdgPositionerV6 +{ + MetaRectangle anchor_rect; + int32_t width; + int32_t height; + uint32_t gravity; + uint32_t anchor; + uint32_t constraint_adjustment; + int32_t offset_x; + int32_t offset_y; +} MetaWaylandZxdgPositionerV6; + +typedef struct _MetaWaylandZxdgSurfaceV6Constructor +{ + MetaWaylandSurface *surface; + struct wl_resource *resource; + MetaWaylandZxdgShellV6Client *shell_client; +} MetaWaylandZxdgSurfaceV6Constructor; + +typedef struct _MetaWaylandZxdgSurfaceV6Private +{ + struct wl_resource *resource; + MetaWaylandZxdgShellV6Client *shell_client; + MetaWaylandSerial acked_configure_serial; + MetaRectangle geometry; + + guint configure_sent : 1; + guint first_buffer_attached : 1; + guint has_set_geometry : 1; +} MetaWaylandZxdgSurfaceV6Private; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandZxdgSurfaceV6, + meta_wayland_zxdg_surface_v6, + META_TYPE_WAYLAND_SHELL_SURFACE); + +struct _MetaWaylandZxdgToplevelV6 +{ + MetaWaylandZxdgSurfaceV6 parent; + + struct wl_resource *resource; +}; + +G_DEFINE_TYPE (MetaWaylandZxdgToplevelV6, + meta_wayland_zxdg_toplevel_v6, + META_TYPE_WAYLAND_ZXDG_SURFACE_V6); + +struct _MetaWaylandZxdgPopupV6 +{ + MetaWaylandZxdgSurfaceV6 parent; + + struct wl_resource *resource; + + MetaWaylandSurface *parent_surface; + struct wl_listener parent_destroy_listener; + + MetaWaylandPopup *popup; + + struct { + MetaWaylandSurface *parent_surface; + + /* + * The coordinates/dimensions in the placement rule are in logical pixel + * coordinate space, i.e. not scaled given what monitor the popup is on. + */ + MetaPlacementRule placement_rule; + + MetaWaylandSeat *grab_seat; + uint32_t grab_serial; + } setup; +}; + +static void +popup_surface_iface_init (MetaWaylandPopupSurfaceInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaWaylandZxdgPopupV6, + meta_wayland_zxdg_popup_v6, + META_TYPE_WAYLAND_ZXDG_SURFACE_V6, + G_IMPLEMENT_INTERFACE (META_TYPE_WAYLAND_POPUP_SURFACE, + popup_surface_iface_init)); + +static MetaPlacementRule +meta_wayland_zxdg_positioner_v6_to_placement (MetaWaylandZxdgPositionerV6 *xdg_positioner); + +static struct wl_resource * +meta_wayland_zxdg_surface_v6_get_shell_resource (MetaWaylandZxdgSurfaceV6 *xdg_surface); + +static MetaRectangle +meta_wayland_zxdg_surface_v6_get_window_geometry (MetaWaylandZxdgSurfaceV6 *xdg_surface); + +static uint32_t +meta_wayland_zxdg_surface_v6_send_configure (MetaWaylandZxdgSurfaceV6 *xdg_surface); + +static MetaWaylandSurface * +surface_from_xdg_surface_resource (struct wl_resource *resource) +{ + MetaWaylandSurfaceRole *surface_role = wl_resource_get_user_data (resource); + + return meta_wayland_surface_role_get_surface (surface_role); +} + +static MetaWaylandSurface * +surface_from_xdg_toplevel_resource (struct wl_resource *resource) +{ + return surface_from_xdg_surface_resource (resource); +} + +static void +zxdg_toplevel_v6_destructor (struct wl_resource *resource) +{ + MetaWaylandZxdgToplevelV6 *xdg_toplevel = + wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + meta_wayland_surface_destroy_window (surface); + xdg_toplevel->resource = NULL; +} + +static void +zxdg_toplevel_v6_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +zxdg_toplevel_v6_set_parent (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent_resource) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + MetaWindow *transient_for = NULL; + + if (parent_resource) + { + MetaWaylandSurface *parent_surface = + surface_from_xdg_surface_resource (parent_resource); + + transient_for = parent_surface->window; + } + + meta_window_set_transient_for (surface->window, transient_for); +} + +static void +zxdg_toplevel_v6_set_title (struct wl_client *client, + struct wl_resource *resource, + const char *title) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + if (!g_utf8_validate (title, -1, NULL)) + title = ""; + + meta_window_set_title (surface->window, title); +} + +static void +zxdg_toplevel_v6_set_app_id (struct wl_client *client, + struct wl_resource *resource, + const char *app_id) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + if (!g_utf8_validate (app_id, -1, NULL)) + app_id = ""; + + meta_window_set_wm_class (surface->window, app_id, app_id); +} + +static void +zxdg_toplevel_v6_show_window_menu (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial, + int32_t x, + int32_t y) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + int monitor_scale; + + if (!meta_wayland_seat_get_grab_info (seat, surface, serial, FALSE, NULL, NULL)) + return; + + monitor_scale = surface->window->monitor->scale; + meta_window_show_menu (surface->window, META_WINDOW_MENU_WM, + surface->window->buffer_rect.x + (x * monitor_scale), + surface->window->buffer_rect.y + (y * monitor_scale)); +} + +static void +zxdg_toplevel_v6_move (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + gfloat x, y; + + if (!meta_wayland_seat_get_grab_info (seat, surface, serial, TRUE, &x, &y)) + return; + + meta_wayland_surface_begin_grab_op (surface, seat, META_GRAB_OP_MOVING, x, y); +} + +static MetaGrabOp +grab_op_for_xdg_toplevel_resize_edge (int edge) +{ + MetaGrabOp op = META_GRAB_OP_WINDOW_BASE; + + if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP) + op |= META_GRAB_OP_WINDOW_DIR_NORTH; + if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM) + op |= META_GRAB_OP_WINDOW_DIR_SOUTH; + if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT) + op |= META_GRAB_OP_WINDOW_DIR_WEST; + if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT) + op |= META_GRAB_OP_WINDOW_DIR_EAST; + + if (op == META_GRAB_OP_WINDOW_BASE) + { + g_warning ("invalid edge: %d", edge); + return META_GRAB_OP_NONE; + } + + return op; +} + +static void +zxdg_toplevel_v6_resize (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial, + uint32_t edges) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + gfloat x, y; + MetaGrabOp grab_op; + + if (!meta_wayland_seat_get_grab_info (seat, surface, serial, TRUE, &x, &y)) + return; + + grab_op = grab_op_for_xdg_toplevel_resize_edge (edges); + meta_wayland_surface_begin_grab_op (surface, seat, grab_op, x, y); +} + +static void +zxdg_toplevel_v6_set_max_size (struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + if (width < 0 || height < 0) + { + wl_resource_post_error (resource, + ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + "invalid negative max size requested %i x %i", + width, height); + return; + } + + surface->pending->has_new_max_size = TRUE; + surface->pending->new_max_width = width; + surface->pending->new_max_height = height; +} + +static void +zxdg_toplevel_v6_set_min_size (struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + if (width < 0 || height < 0) + { + wl_resource_post_error (resource, + ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + "invalid negative min size requested %i x %i", + width, height); + return; + } + + surface->pending->has_new_min_size = TRUE; + surface->pending->new_min_width = width; + surface->pending->new_min_height = height; +} + +static void +zxdg_toplevel_v6_set_maximized (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + meta_window_force_placement (surface->window, TRUE); + meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); +} + +static void +zxdg_toplevel_v6_unset_maximized (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH); +} + +static void +zxdg_toplevel_v6_set_fullscreen (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output_resource) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + if (output_resource) + { + MetaWaylandOutput *output = wl_resource_get_user_data (output_resource); + if (output) + meta_window_move_to_monitor (surface->window, output->logical_monitor->number); + } + + meta_window_make_fullscreen (surface->window); +} + +static void +zxdg_toplevel_v6_unset_fullscreen (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + meta_window_unmake_fullscreen (surface->window); +} + +static void +zxdg_toplevel_v6_set_minimized (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); + + meta_window_minimize (surface->window); +} + +static const struct zxdg_toplevel_v6_interface meta_wayland_zxdg_toplevel_v6_interface = { + zxdg_toplevel_v6_destroy, + zxdg_toplevel_v6_set_parent, + zxdg_toplevel_v6_set_title, + zxdg_toplevel_v6_set_app_id, + zxdg_toplevel_v6_show_window_menu, + zxdg_toplevel_v6_move, + zxdg_toplevel_v6_resize, + zxdg_toplevel_v6_set_max_size, + zxdg_toplevel_v6_set_min_size, + zxdg_toplevel_v6_set_maximized, + zxdg_toplevel_v6_unset_maximized, + zxdg_toplevel_v6_set_fullscreen, + zxdg_toplevel_v6_unset_fullscreen, + zxdg_toplevel_v6_set_minimized, +}; + +static void +zxdg_popup_v6_destructor (struct wl_resource *resource) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = + META_WAYLAND_ZXDG_POPUP_V6 (wl_resource_get_user_data (resource)); + + if (xdg_popup->parent_surface) + { + wl_list_remove (&xdg_popup->parent_destroy_listener.link); + xdg_popup->parent_surface = NULL; + } + + if (xdg_popup->popup) + meta_wayland_popup_dismiss (xdg_popup->popup); + + xdg_popup->resource = NULL; +} + +static void +zxdg_popup_v6_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +zxdg_popup_v6_grab (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = + META_WAYLAND_ZXDG_POPUP_V6 (wl_resource_get_user_data (resource)); + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *parent_surface; + + parent_surface = xdg_popup->setup.parent_surface; + if (!parent_surface) + { + wl_resource_post_error (resource, + ZXDG_POPUP_V6_ERROR_INVALID_GRAB, + "tried to grab after popup was mapped"); + return; + } + + xdg_popup->setup.grab_seat = seat; + xdg_popup->setup.grab_serial = serial; +} + +static const struct zxdg_popup_v6_interface meta_wayland_zxdg_popup_v6_interface = { + zxdg_popup_v6_destroy, + zxdg_popup_v6_grab, +}; + +static void +handle_popup_parent_destroyed (struct wl_listener *listener, + void *data) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = + wl_container_of (listener, xdg_popup, parent_destroy_listener); + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (xdg_popup); + struct wl_resource *xdg_shell_resource = + meta_wayland_zxdg_surface_v6_get_shell_resource (xdg_surface); + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (xdg_popup); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + wl_resource_post_error (xdg_shell_resource, + ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + "destroyed popup not top most popup"); + xdg_popup->parent_surface = NULL; + + meta_wayland_surface_destroy_window (surface); +} + +static void +fill_states (struct wl_array *states, + MetaWindow *window) +{ + uint32_t *s; + + if (META_WINDOW_MAXIMIZED (window)) + { + s = wl_array_add (states, sizeof *s); + *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; + } + if (meta_window_is_fullscreen (window)) + { + s = wl_array_add (states, sizeof *s); + *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; + } + if (meta_grab_op_is_resizing (window->display->grab_op)) + { + s = wl_array_add (states, sizeof *s); + *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; + } + if (meta_window_appears_focused (window)) + { + s = wl_array_add (states, sizeof *s); + *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; + } +} + +static void +meta_wayland_zxdg_toplevel_v6_send_configure (MetaWaylandZxdgToplevelV6 *xdg_toplevel, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (xdg_toplevel); + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (xdg_toplevel); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + struct wl_array states; + uint32_t serial; + + wl_array_init (&states); + fill_states (&states, surface->window); + + zxdg_toplevel_v6_send_configure (xdg_toplevel->resource, + new_width, new_height, + &states); + wl_array_release (&states); + + serial = meta_wayland_zxdg_surface_v6_send_configure (xdg_surface); + + if (sent_serial) + { + sent_serial->set = TRUE; + sent_serial->value = serial; + } +} + +static gboolean +is_new_size_hints_valid (MetaWindow *window, + MetaWaylandPendingState *pending) +{ + int new_min_width, new_min_height; + int new_max_width, new_max_height; + + if (pending->has_new_min_size) + { + new_min_width = pending->new_min_width; + new_min_height = pending->new_min_height; + } + else + { + meta_window_wayland_get_min_size (window, &new_min_width, &new_min_height); + } + + if (pending->has_new_max_size) + { + new_max_width = pending->new_max_width; + new_max_height = pending->new_max_height; + } + else + { + meta_window_wayland_get_max_size (window, &new_max_width, &new_max_height); + } + /* Zero means unlimited */ + return ((new_max_width == 0 || new_min_width <= new_max_width) && + (new_max_height == 0 || new_min_height <= new_max_height)); +} + +static void +meta_wayland_zxdg_toplevel_v6_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandPendingState *pending) +{ + MetaWaylandZxdgToplevelV6 *xdg_toplevel = + META_WAYLAND_ZXDG_TOPLEVEL_V6 (surface_role); + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (xdg_toplevel); + MetaWaylandZxdgSurfaceV6Private *xdg_surface_priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + MetaWindow *window = surface->window; + MetaRectangle window_geometry; + + surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_zxdg_toplevel_v6_parent_class); + surface_role_class->commit (surface_role, pending); + + if (!xdg_surface_priv->configure_sent) + { + meta_wayland_zxdg_toplevel_v6_send_configure (xdg_toplevel, 0, 0, NULL); + return; + } + + if (!pending->newly_attached) + return; + + /* If the window disappeared the surface is not coming back. */ + if (!window) + return; + + if (pending->has_new_geometry) + { + window_geometry = + meta_wayland_zxdg_surface_v6_get_window_geometry (xdg_surface); + meta_window_wayland_move_resize (window, + &xdg_surface_priv->acked_configure_serial, + window_geometry, + pending->dx, pending->dy); + } + else if (pending->dx != 0 || pending->dx != 0) + { + g_warning ("XXX: Attach-initiated move without a new geometry. " + "This is unimplemented right now."); + } + + /* When we get to this point, we ought to have valid size hints */ + if (pending->has_new_min_size || pending->has_new_max_size) + { + if (is_new_size_hints_valid (window, pending)) + { + if (pending->has_new_min_size) + meta_window_wayland_set_min_size (window, + pending->new_min_width, + pending->new_min_height); + + if (pending->has_new_max_size) + meta_window_wayland_set_max_size (window, + pending->new_max_width, + pending->new_max_height); + + meta_window_recalc_features (window); + } + else + { + wl_resource_post_error (surface->resource, + ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + "Invalid min/max size"); + + } + } + + xdg_surface_priv->acked_configure_serial.set = FALSE; +} + +static MetaWaylandSurface * +meta_wayland_zxdg_toplevel_v6_get_toplevel (MetaWaylandSurfaceRole *surface_role) +{ + return meta_wayland_surface_role_get_surface (surface_role); +} + +static void +meta_wayland_zxdg_toplevel_v6_configure (MetaWaylandShellSurface *shell_surface, + int new_x, + int new_y, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial) +{ + MetaWaylandZxdgToplevelV6 *xdg_toplevel = + META_WAYLAND_ZXDG_TOPLEVEL_V6 (shell_surface); + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (xdg_toplevel); + MetaWaylandZxdgSurfaceV6Private *xdg_surface_priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + if (!xdg_surface_priv->resource) + return; + + if (!xdg_toplevel->resource) + return; + + meta_wayland_zxdg_toplevel_v6_send_configure (xdg_toplevel, + new_width, new_height, + sent_serial); +} + +static void +meta_wayland_zxdg_toplevel_v6_managed (MetaWaylandShellSurface *shell_surface, + MetaWindow *window) +{ +} + +static void +meta_wayland_zxdg_toplevel_v6_close (MetaWaylandShellSurface *shell_surface) +{ + MetaWaylandZxdgToplevelV6 *xdg_toplevel = + META_WAYLAND_ZXDG_TOPLEVEL_V6 (shell_surface); + + zxdg_toplevel_v6_send_close (xdg_toplevel->resource); +} + +static void +meta_wayland_zxdg_toplevel_v6_shell_client_destroyed (MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ + MetaWaylandZxdgToplevelV6 *xdg_toplevel = + META_WAYLAND_ZXDG_TOPLEVEL_V6 (xdg_surface); + struct wl_resource *xdg_shell_resource = + meta_wayland_zxdg_surface_v6_get_shell_resource (xdg_surface); + MetaWaylandZxdgSurfaceV6Class *xdg_surface_class = + META_WAYLAND_ZXDG_SURFACE_V6_CLASS (meta_wayland_zxdg_toplevel_v6_parent_class); + + xdg_surface_class->shell_client_destroyed (xdg_surface); + + if (xdg_toplevel->resource) + { + wl_resource_post_error (xdg_shell_resource, + ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, + "xdg_shell of xdg_toplevel@%d was destroyed", + wl_resource_get_id (xdg_toplevel->resource)); + + wl_resource_destroy (xdg_toplevel->resource); + } +} + +static void +meta_wayland_zxdg_toplevel_v6_finalize (GObject *object) +{ + MetaWaylandZxdgToplevelV6 *xdg_toplevel = + META_WAYLAND_ZXDG_TOPLEVEL_V6 (object); + + g_clear_pointer (&xdg_toplevel->resource, wl_resource_destroy); + + G_OBJECT_CLASS (meta_wayland_zxdg_toplevel_v6_parent_class)->finalize (object); +} + +static void +meta_wayland_zxdg_toplevel_v6_init (MetaWaylandZxdgToplevelV6 *role) +{ +} + +static void +meta_wayland_zxdg_toplevel_v6_class_init (MetaWaylandZxdgToplevelV6Class *klass) +{ + GObjectClass *object_class; + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandShellSurfaceClass *shell_surface_class; + MetaWaylandZxdgSurfaceV6Class *xdg_surface_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = meta_wayland_zxdg_toplevel_v6_finalize; + + surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass); + surface_role_class->commit = meta_wayland_zxdg_toplevel_v6_commit; + surface_role_class->get_toplevel = meta_wayland_zxdg_toplevel_v6_get_toplevel; + + shell_surface_class = META_WAYLAND_SHELL_SURFACE_CLASS (klass); + shell_surface_class->configure = meta_wayland_zxdg_toplevel_v6_configure; + shell_surface_class->managed = meta_wayland_zxdg_toplevel_v6_managed; + shell_surface_class->close = meta_wayland_zxdg_toplevel_v6_close; + + xdg_surface_class = META_WAYLAND_ZXDG_SURFACE_V6_CLASS (klass); + xdg_surface_class->shell_client_destroyed = + meta_wayland_zxdg_toplevel_v6_shell_client_destroyed; +} + +static void +scale_placement_rule (MetaPlacementRule *placement_rule, + MetaWaylandSurface *surface) +{ + int geometry_scale; + + geometry_scale = meta_window_wayland_get_geometry_scale (surface->window); + + placement_rule->anchor_rect.x *= geometry_scale; + placement_rule->anchor_rect.y *= geometry_scale; + placement_rule->anchor_rect.width *= geometry_scale; + placement_rule->anchor_rect.height *= geometry_scale; + placement_rule->offset_x *= geometry_scale; + placement_rule->offset_y *= geometry_scale; + placement_rule->width *= geometry_scale; + placement_rule->height *= geometry_scale; +} + +static void +finish_popup_setup (MetaWaylandZxdgPopupV6 *xdg_popup) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (xdg_popup); + MetaWaylandShellSurface *shell_surface = + META_WAYLAND_SHELL_SURFACE (xdg_popup); + MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (xdg_popup); + struct wl_resource *xdg_shell_resource = + meta_wayland_zxdg_surface_v6_get_shell_resource (xdg_surface); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + MetaWaylandSurface *parent_surface; + MetaPlacementRule scaled_placement_rule; + MetaWaylandSeat *seat; + uint32_t serial; + MetaDisplay *display = meta_get_display (); + MetaWindow *window; + + parent_surface = xdg_popup->setup.parent_surface; + seat = xdg_popup->setup.grab_seat; + serial = xdg_popup->setup.grab_serial; + + xdg_popup->setup.parent_surface = NULL; + xdg_popup->setup.grab_seat = NULL; + + if (!parent_surface->window) + { + zxdg_popup_v6_send_popup_done (xdg_popup->resource); + return; + } + + if (seat) + { + MetaWaylandSurface *top_popup; + + if (!meta_wayland_seat_can_popup (seat, serial)) + { + zxdg_popup_v6_send_popup_done (xdg_popup->resource); + return; + } + + top_popup = meta_wayland_pointer_get_top_popup (seat->pointer); + if (top_popup && parent_surface != top_popup) + { + wl_resource_post_error (xdg_shell_resource, + ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + "parent not top most surface"); + return; + } + } + + xdg_popup->parent_surface = parent_surface; + xdg_popup->parent_destroy_listener.notify = handle_popup_parent_destroyed; + wl_resource_add_destroy_listener (parent_surface->resource, + &xdg_popup->parent_destroy_listener); + + window = meta_window_wayland_new (display, surface); + meta_wayland_shell_surface_set_window (shell_surface, window); + + scaled_placement_rule = xdg_popup->setup.placement_rule; + scale_placement_rule (&scaled_placement_rule, surface); + meta_window_place_with_placement_rule (window, &scaled_placement_rule); + + if (seat) + { + MetaWaylandPopupSurface *popup_surface; + MetaWaylandPopup *popup; + + meta_window_focus (window, meta_display_get_current_time (display)); + popup_surface = META_WAYLAND_POPUP_SURFACE (surface->role); + popup = meta_wayland_pointer_start_popup_grab (seat->pointer, + popup_surface); + if (popup == NULL) + { + zxdg_popup_v6_send_popup_done (xdg_popup->resource); + meta_wayland_surface_destroy_window (surface); + return; + } + + xdg_popup->popup = popup; + } + else + { + /* The keyboard focus semantics for non-grabbing zxdg_shell_v6 popups + * is pretty undefined. Same applies for subsurfaces, but in practice, + * subsurfaces never receive keyboard focus, so it makes sense to + * do the same for non-grabbing popups. + * + * See https://bugzilla.gnome.org/show_bug.cgi?id=771694#c24 + */ + window->input = FALSE; + } +} + +static void +meta_wayland_zxdg_popup_v6_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandPendingState *pending) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = META_WAYLAND_ZXDG_POPUP_V6 (surface_role); + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (surface_role); + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + MetaRectangle window_geometry; + + if (xdg_popup->setup.parent_surface) + finish_popup_setup (xdg_popup); + + surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_zxdg_popup_v6_parent_class); + surface_role_class->commit (surface_role, pending); + + /* If the window disappeared the surface is not coming back. */ + if (!surface->window) + return; + + if (!pending->newly_attached) + return; + + if (!surface->buffer_ref.buffer) + return; + + window_geometry = + meta_wayland_zxdg_surface_v6_get_window_geometry (xdg_surface); + meta_window_wayland_move_resize (surface->window, + NULL, + window_geometry, + pending->dx, pending->dy); +} + +static MetaWaylandSurface * +meta_wayland_zxdg_popup_v6_get_toplevel (MetaWaylandSurfaceRole *surface_role) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = META_WAYLAND_ZXDG_POPUP_V6 (surface_role); + + if (xdg_popup->parent_surface) + return meta_wayland_surface_get_toplevel (xdg_popup->parent_surface); + else + return NULL; +} + +static void +meta_wayland_zxdg_popup_v6_configure (MetaWaylandShellSurface *shell_surface, + int new_x, + int new_y, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = + META_WAYLAND_ZXDG_POPUP_V6 (shell_surface); + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (xdg_popup); + MetaWindow *parent_window = xdg_popup->parent_surface->window; + int geometry_scale; + int x, y; + + /* If the parent surface was destroyed, its window will be destroyed + * before the popup receives the parent-destroy signal. This means that + * the popup may potentially get temporary focus until itself is destroyed. + * If this happen, don't try to configure the xdg_popup surface. + * + * FIXME: Could maybe add a signal that is emitted before the window is + * created so that we can avoid incorrect intermediate foci. + */ + if (!parent_window) + return; + + geometry_scale = meta_window_wayland_get_geometry_scale (parent_window); + x = (new_x - parent_window->rect.x) / geometry_scale; + y = (new_y - parent_window->rect.y) / geometry_scale; + zxdg_popup_v6_send_configure (xdg_popup->resource, + x, y, new_width, new_height); + meta_wayland_zxdg_surface_v6_send_configure (xdg_surface); +} + +static void +meta_wayland_zxdg_popup_v6_managed (MetaWaylandShellSurface *shell_surface, + MetaWindow *window) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = + META_WAYLAND_ZXDG_POPUP_V6 (shell_surface); + MetaWaylandSurface *parent = xdg_popup->parent_surface; + + g_assert (parent); + + meta_window_set_transient_for (window, parent->window); + meta_window_set_type (window, META_WINDOW_DROPDOWN_MENU); +} + +static void +meta_wayland_zxdg_popup_v6_shell_client_destroyed (MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = META_WAYLAND_ZXDG_POPUP_V6 (xdg_surface); + struct wl_resource *xdg_shell_resource = + meta_wayland_zxdg_surface_v6_get_shell_resource (xdg_surface); + MetaWaylandZxdgSurfaceV6Class *xdg_surface_class = + META_WAYLAND_ZXDG_SURFACE_V6_CLASS (meta_wayland_zxdg_popup_v6_parent_class); + + xdg_surface_class->shell_client_destroyed (xdg_surface); + + if (xdg_popup->resource) + { + wl_resource_post_error (xdg_shell_resource, + ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, + "xdg_shell of xdg_popup@%d was destroyed", + wl_resource_get_id (xdg_popup->resource)); + + wl_resource_destroy (xdg_popup->resource); + } +} + +static void +meta_wayland_zxdg_popup_v6_done (MetaWaylandPopupSurface *popup_surface) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = META_WAYLAND_ZXDG_POPUP_V6 (popup_surface); + + zxdg_popup_v6_send_popup_done (xdg_popup->resource); +} + +static void +meta_wayland_zxdg_popup_v6_dismiss (MetaWaylandPopupSurface *popup_surface) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = + META_WAYLAND_ZXDG_POPUP_V6 (popup_surface); + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (xdg_popup); + struct wl_resource *xdg_shell_resource = + meta_wayland_zxdg_surface_v6_get_shell_resource (xdg_surface); + MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (xdg_popup); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + MetaWaylandSurface *top_popup; + + top_popup = meta_wayland_popup_get_top_popup (xdg_popup->popup); + if (surface != top_popup) + { + wl_resource_post_error (xdg_shell_resource, + ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + "destroyed popup not top most popup"); + } + + xdg_popup->popup = NULL; + + meta_wayland_surface_destroy_window (surface); +} + +static MetaWaylandSurface * +meta_wayland_zxdg_popup_v6_get_surface (MetaWaylandPopupSurface *popup_surface) +{ + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (popup_surface); + + return meta_wayland_surface_role_get_surface (surface_role); +} + +static void +popup_surface_iface_init (MetaWaylandPopupSurfaceInterface *iface) +{ + iface->done = meta_wayland_zxdg_popup_v6_done; + iface->dismiss = meta_wayland_zxdg_popup_v6_dismiss; + iface->get_surface = meta_wayland_zxdg_popup_v6_get_surface; +} + +static void +meta_wayland_zxdg_popup_v6_role_finalize (GObject *object) +{ + MetaWaylandZxdgPopupV6 *xdg_popup = META_WAYLAND_ZXDG_POPUP_V6 (object); + + g_clear_pointer (&xdg_popup->resource, wl_resource_destroy); + + G_OBJECT_CLASS (meta_wayland_zxdg_popup_v6_parent_class)->finalize (object); +} + +static void +meta_wayland_zxdg_popup_v6_init (MetaWaylandZxdgPopupV6 *role) +{ +} + +static void +meta_wayland_zxdg_popup_v6_class_init (MetaWaylandZxdgPopupV6Class *klass) +{ + GObjectClass *object_class; + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandShellSurfaceClass *shell_surface_class; + MetaWaylandZxdgSurfaceV6Class *xdg_surface_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = meta_wayland_zxdg_popup_v6_role_finalize; + + surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass); + surface_role_class->commit = meta_wayland_zxdg_popup_v6_commit; + surface_role_class->get_toplevel = meta_wayland_zxdg_popup_v6_get_toplevel; + + shell_surface_class = META_WAYLAND_SHELL_SURFACE_CLASS (klass); + shell_surface_class->configure = meta_wayland_zxdg_popup_v6_configure; + shell_surface_class->managed = meta_wayland_zxdg_popup_v6_managed; + + xdg_surface_class = META_WAYLAND_ZXDG_SURFACE_V6_CLASS (klass); + xdg_surface_class->shell_client_destroyed = + meta_wayland_zxdg_popup_v6_shell_client_destroyed; +} + +static struct wl_resource * +meta_wayland_zxdg_surface_v6_get_shell_resource (MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + return priv->shell_client->resource; +} + +static MetaRectangle +meta_wayland_zxdg_surface_v6_get_window_geometry (MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + return priv->geometry; +} + +static gboolean +meta_wayland_zxdg_surface_v6_is_assigned (MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + return priv->resource != NULL; +} + +static uint32_t +meta_wayland_zxdg_surface_v6_send_configure (MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + struct wl_display *display; + uint32_t serial; + + display = wl_client_get_display (wl_resource_get_client (priv->resource)); + serial = wl_display_next_serial (display); + zxdg_surface_v6_send_configure (priv->resource, serial); + + priv->configure_sent = TRUE; + + return serial; +} + +static void +zxdg_surface_v6_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandZxdgSurfaceV6 *xdg_surface = wl_resource_get_user_data (resource); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, + surface); + + priv->shell_client->surfaces = g_list_remove (priv->shell_client->surfaces, + xdg_surface); + + priv->resource = NULL; + priv->first_buffer_attached = FALSE; +} + +static void +zxdg_surface_v6_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +zxdg_surface_v6_get_toplevel (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + struct wl_resource *xdg_shell_resource = + meta_wayland_zxdg_surface_v6_get_shell_resource (xdg_surface); + + wl_resource_post_error (xdg_shell_resource, ZXDG_SHELL_V6_ERROR_ROLE, + "wl_surface@%d already has a role assigned", + wl_resource_get_id (surface->resource)); +} + +static void +zxdg_surface_v6_get_popup (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *parent_resource, + struct wl_resource *positioner_resource) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = wl_resource_get_user_data (resource); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + + wl_resource_post_error (priv->shell_client->resource, + ZXDG_SHELL_V6_ERROR_ROLE, + "wl_surface@%d already has a role assigned", + wl_resource_get_id (surface->resource)); +} + +static void +zxdg_surface_v6_set_window_geometry (struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + + surface->pending->has_new_geometry = TRUE; + surface->pending->new_geometry.x = x; + surface->pending->new_geometry.y = y; + surface->pending->new_geometry.width = width; + surface->pending->new_geometry.height = height; +} + +static void +zxdg_surface_v6_ack_configure (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = wl_resource_get_user_data (resource); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + priv->acked_configure_serial.set = TRUE; + priv->acked_configure_serial.value = serial; +} + +static const struct zxdg_surface_v6_interface meta_wayland_zxdg_surface_v6_interface = { + zxdg_surface_v6_destroy, + zxdg_surface_v6_get_toplevel, + zxdg_surface_v6_get_popup, + zxdg_surface_v6_set_window_geometry, + zxdg_surface_v6_ack_configure, +}; + +static void +meta_wayland_zxdg_surface_v6_finalize (GObject *object) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = META_WAYLAND_ZXDG_SURFACE_V6 (object); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + g_clear_pointer (&priv->resource, wl_resource_destroy); + + G_OBJECT_CLASS (meta_wayland_zxdg_surface_v6_parent_class)->finalize (object); +} + +static void +meta_wayland_zxdg_surface_v6_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandPendingState *pending) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (surface_role); + MetaWaylandShellSurface *shell_surface = + META_WAYLAND_SHELL_SURFACE (xdg_surface); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + MetaWindow *window = surface->window; + MetaWaylandSurfaceRoleClass *surface_role_class; + + surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_zxdg_surface_v6_parent_class); + surface_role_class->commit (surface_role, pending); + + /* Ignore commits when unassigned. */ + if (!priv->resource) + return; + + if (surface->buffer_ref.buffer == NULL && priv->first_buffer_attached) + { + /* XDG surfaces can't commit NULL buffers */ + wl_resource_post_error (surface->resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Cannot commit a NULL buffer to an xdg_surface"); + return; + } + + if (surface->buffer_ref.buffer && !priv->configure_sent) + { + wl_resource_post_error (surface->resource, + ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, + "buffer committed to unconfigured xdg_surface"); + return; + } + + if (!window) + return; + + if (surface->buffer_ref.buffer) + priv->first_buffer_attached = TRUE; + else + return; + + if (pending->has_new_geometry) + { + /* If we have new geometry, use it. */ + priv->geometry = pending->new_geometry; + priv->has_set_geometry = TRUE; + } + else if (!priv->has_set_geometry) + { + MetaRectangle new_geometry = { 0 }; + + /* If the surface has never set any geometry, calculate + * a default one unioning the surface and all subsurfaces together. */ + + meta_wayland_shell_surface_calculate_geometry (shell_surface, + &new_geometry); + if (!meta_rectangle_equal (&new_geometry, &priv->geometry)) + { + pending->has_new_geometry = TRUE; + priv->geometry = new_geometry; + } + } +} + +static void +meta_wayland_zxdg_surface_v6_assigned (MetaWaylandSurfaceRole *surface_role) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (surface_role); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + struct wl_resource *xdg_shell_resource = + meta_wayland_zxdg_surface_v6_get_shell_resource (xdg_surface); + MetaWaylandSurfaceRoleClass *surface_role_class; + + priv->configure_sent = FALSE; + priv->first_buffer_attached = FALSE; + + if (surface->buffer_ref.buffer) + { + wl_resource_post_error (xdg_shell_resource, + ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + "wl_surface@%d already has a buffer committed", + wl_resource_get_id (surface->resource)); + return; + } + + surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_zxdg_surface_v6_parent_class); + surface_role_class->assigned (surface_role); +} + +static void +meta_wayland_zxdg_surface_v6_ping (MetaWaylandShellSurface *shell_surface, + uint32_t serial) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = + META_WAYLAND_ZXDG_SURFACE_V6 (shell_surface); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + zxdg_shell_v6_send_ping (priv->shell_client->resource, serial); +} + +static void +meta_wayland_zxdg_surface_v6_real_shell_client_destroyed (MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + if (priv->resource) + { + wl_resource_post_error (priv->shell_client->resource, + ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, + "xdg_shell of xdg_surface@%d was destroyed", + wl_resource_get_id (priv->resource)); + + wl_resource_destroy (priv->resource); + } +} + +static void +meta_wayland_zxdg_surface_v6_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = META_WAYLAND_ZXDG_SURFACE_V6 (object); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + switch (prop_id) + { + case ZXDG_SURFACE_V6_PROP_SHELL_CLIENT: + priv->shell_client = g_value_get_pointer (value); + break; + + case ZXDG_SURFACE_V6_PROP_RESOURCE: + priv->resource = g_value_get_pointer (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_wayland_zxdg_surface_v6_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaWaylandZxdgSurfaceV6 *xdg_surface = META_WAYLAND_ZXDG_SURFACE_V6 (object); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + + switch (prop_id) + { + case ZXDG_SURFACE_V6_PROP_SHELL_CLIENT: + g_value_set_pointer (value, priv->shell_client); + break; + + case ZXDG_SURFACE_V6_PROP_RESOURCE: + g_value_set_pointer (value, priv->resource); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_wayland_zxdg_surface_v6_init (MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ +} + +static void +meta_wayland_zxdg_surface_v6_class_init (MetaWaylandZxdgSurfaceV6Class *klass) +{ + GObjectClass *object_class; + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandShellSurfaceClass *shell_surface_class; + GParamSpec *pspec; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = meta_wayland_zxdg_surface_v6_finalize; + object_class->set_property = meta_wayland_zxdg_surface_v6_set_property; + object_class->get_property = meta_wayland_zxdg_surface_v6_get_property; + + surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass); + surface_role_class->commit = meta_wayland_zxdg_surface_v6_commit; + surface_role_class->assigned = meta_wayland_zxdg_surface_v6_assigned; + + shell_surface_class = META_WAYLAND_SHELL_SURFACE_CLASS (klass); + shell_surface_class->ping = meta_wayland_zxdg_surface_v6_ping; + + klass->shell_client_destroyed = + meta_wayland_zxdg_surface_v6_real_shell_client_destroyed; + + pspec = g_param_spec_pointer ("shell-client", + "MetaWaylandZxdgShellV6Client", + "The shell client instance", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, + ZXDG_SURFACE_V6_PROP_SHELL_CLIENT, + pspec); + pspec = g_param_spec_pointer ("xdg-surface-resource", + "xdg_surface wl_resource", + "The xdg_surface wl_resource instance", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, + ZXDG_SURFACE_V6_PROP_RESOURCE, + pspec); +} + +static void +meta_wayland_zxdg_surface_v6_shell_client_destroyed (MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ + MetaWaylandZxdgSurfaceV6Class *xdg_surface_class = + META_WAYLAND_ZXDG_SURFACE_V6_GET_CLASS (xdg_surface); + + xdg_surface_class->shell_client_destroyed (xdg_surface); +} + +static void +meta_wayland_zxdg_surface_v6_constructor_finalize (MetaWaylandZxdgSurfaceV6Constructor *constructor, + MetaWaylandZxdgSurfaceV6 *xdg_surface) +{ + MetaWaylandZxdgShellV6Client *shell_client = constructor->shell_client; + + shell_client->surface_constructors = + g_list_remove (shell_client->surface_constructors, constructor); + shell_client->surfaces = g_list_append (shell_client->surfaces, xdg_surface); + + wl_resource_set_implementation (constructor->resource, + &meta_wayland_zxdg_surface_v6_interface, + xdg_surface, + zxdg_surface_v6_destructor); + + g_free (constructor); +} + +static void +zxdg_surface_v6_constructor_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_post_error (resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "xdg_surface destroyed before constructed"); + wl_resource_destroy (resource); +} + +static void +zxdg_surface_v6_constructor_get_toplevel (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + MetaWaylandZxdgSurfaceV6Constructor *constructor = + wl_resource_get_user_data (resource); + MetaWaylandZxdgShellV6Client *shell_client = constructor->shell_client; + struct wl_resource *xdg_surface_resource = constructor->resource; + MetaWaylandSurface *surface = constructor->surface; + MetaWaylandZxdgToplevelV6 *xdg_toplevel; + MetaWaylandZxdgSurfaceV6 *xdg_surface; + MetaWaylandShellSurface *shell_surface; + MetaWindow *window; + + if (!meta_wayland_surface_assign_role (surface, + META_TYPE_WAYLAND_ZXDG_TOPLEVEL_V6, + "shell-client", shell_client, + "xdg-surface-resource", xdg_surface_resource, + NULL)) + { + wl_resource_post_error (resource, ZXDG_SHELL_V6_ERROR_ROLE, + "wl_surface@%d already has a different role", + wl_resource_get_id (surface->resource)); + return; + } + + xdg_toplevel = META_WAYLAND_ZXDG_TOPLEVEL_V6 (surface->role); + xdg_toplevel->resource = wl_resource_create (client, + &zxdg_toplevel_v6_interface, + wl_resource_get_version (resource), + id); + wl_resource_set_implementation (xdg_toplevel->resource, + &meta_wayland_zxdg_toplevel_v6_interface, + xdg_toplevel, + zxdg_toplevel_v6_destructor); + + xdg_surface = META_WAYLAND_ZXDG_SURFACE_V6 (xdg_toplevel); + meta_wayland_zxdg_surface_v6_constructor_finalize (constructor, xdg_surface); + + window = meta_window_wayland_new (meta_get_display (), surface); + shell_surface = META_WAYLAND_SHELL_SURFACE (xdg_surface); + meta_wayland_shell_surface_set_window (shell_surface, window); +} + +static void +zxdg_surface_v6_constructor_get_popup (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *parent_resource, + struct wl_resource *positioner_resource) +{ + MetaWaylandZxdgSurfaceV6Constructor *constructor = + wl_resource_get_user_data (resource); + MetaWaylandZxdgShellV6Client *shell_client = constructor->shell_client; + MetaWaylandSurface *surface = constructor->surface; + struct wl_resource *xdg_shell_resource = constructor->shell_client->resource; + struct wl_resource *xdg_surface_resource = constructor->resource; + MetaWaylandSurface *parent_surface = + surface_from_xdg_surface_resource (parent_resource); + MetaWaylandZxdgPositionerV6 *xdg_positioner; + MetaWaylandZxdgPopupV6 *xdg_popup; + MetaWaylandZxdgSurfaceV6 *xdg_surface; + + if (!meta_wayland_surface_assign_role (surface, + META_TYPE_WAYLAND_ZXDG_POPUP_V6, + "shell-client", shell_client, + "xdg-surface-resource", xdg_surface_resource, + NULL)) + { + wl_resource_post_error (xdg_shell_resource, ZXDG_SHELL_V6_ERROR_ROLE, + "wl_surface@%d already has a different role", + wl_resource_get_id (surface->resource)); + return; + } + + if (!META_IS_WAYLAND_ZXDG_SURFACE_V6 (parent_surface->role)) + { + wl_resource_post_error (xdg_shell_resource, + ZXDG_SHELL_V6_ERROR_INVALID_POPUP_PARENT, + "Invalid popup parent role"); + return; + } + + xdg_popup = META_WAYLAND_ZXDG_POPUP_V6 (surface->role); + + xdg_popup->resource = wl_resource_create (client, + &zxdg_popup_v6_interface, + wl_resource_get_version (resource), + id); + wl_resource_set_implementation (xdg_popup->resource, + &meta_wayland_zxdg_popup_v6_interface, + xdg_popup, + zxdg_popup_v6_destructor); + + xdg_surface = META_WAYLAND_ZXDG_SURFACE_V6 (xdg_popup); + meta_wayland_zxdg_surface_v6_constructor_finalize (constructor, xdg_surface); + + xdg_positioner = wl_resource_get_user_data (positioner_resource); + xdg_popup->setup.placement_rule = + meta_wayland_zxdg_positioner_v6_to_placement (xdg_positioner); + xdg_popup->setup.parent_surface = parent_surface; +} + +static void +zxdg_surface_v6_constructor_set_window_geometry (struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + wl_resource_post_error (resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "xdg_surface::set_window_geometry called before constructed"); +} + +static void +zxdg_surface_v6_constructor_ack_configure (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) +{ + wl_resource_post_error (resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "xdg_surface::ack_configure called before constructed"); +} + +static const struct zxdg_surface_v6_interface meta_wayland_zxdg_surface_v6_constructor_interface = { + zxdg_surface_v6_constructor_destroy, + zxdg_surface_v6_constructor_get_toplevel, + zxdg_surface_v6_constructor_get_popup, + zxdg_surface_v6_constructor_set_window_geometry, + zxdg_surface_v6_constructor_ack_configure, +}; + +static void +zxdg_surface_v6_constructor_destructor (struct wl_resource *resource) +{ + MetaWaylandZxdgSurfaceV6Constructor *constructor = + wl_resource_get_user_data (resource); + + constructor->shell_client->surface_constructors = + g_list_remove (constructor->shell_client->surface_constructors, + constructor); + + g_free (constructor); +} + +static MetaPlacementRule +meta_wayland_zxdg_positioner_v6_to_placement (MetaWaylandZxdgPositionerV6 *xdg_positioner) +{ + return (MetaPlacementRule) { + .anchor_rect = xdg_positioner->anchor_rect, + .gravity = xdg_positioner->gravity, + .anchor = xdg_positioner->anchor, + .constraint_adjustment = xdg_positioner->constraint_adjustment, + .offset_x = xdg_positioner->offset_x, + .offset_y = xdg_positioner->offset_y, + .width = xdg_positioner->width, + .height = xdg_positioner->height, + }; +} + +static void +zxdg_positioner_v6_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +zxdg_positioner_v6_set_size (struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height) +{ + MetaWaylandZxdgPositionerV6 *positioner = wl_resource_get_user_data (resource); + + if (width <= 0 || height <= 0) + { + wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + "Invalid size"); + return; + } + + positioner->width = width; + positioner->height = height; +} + +static void +zxdg_positioner_v6_set_anchor_rect (struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + MetaWaylandZxdgPositionerV6 *positioner = wl_resource_get_user_data (resource); + + if (width <= 0 || height <= 0) + { + wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + "Invalid anchor rectangle size"); + return; + } + + positioner->anchor_rect = (MetaRectangle) { + .x = x, + .y = y, + .width = width, + .height = height, + }; +} + +static void +zxdg_positioner_v6_set_anchor (struct wl_client *client, + struct wl_resource *resource, + uint32_t anchor) +{ + MetaWaylandZxdgPositionerV6 *positioner = wl_resource_get_user_data (resource); + + if ((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT && + anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) || + (anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP && + anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) + { + wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + "Invalid anchor"); + return; + } + + positioner->anchor = anchor; +} + +static void +zxdg_positioner_v6_set_gravity (struct wl_client *client, + struct wl_resource *resource, + uint32_t gravity) +{ + MetaWaylandZxdgPositionerV6 *positioner = wl_resource_get_user_data (resource); + + if ((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT && + gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT) || + (gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP && + gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) + { + wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + "Invalid gravity"); + return; + } + + positioner->gravity = gravity; +} + +static void +zxdg_positioner_v6_set_constraint_adjustment (struct wl_client *client, + struct wl_resource *resource, + uint32_t constraint_adjustment) +{ + MetaWaylandZxdgPositionerV6 *positioner = wl_resource_get_user_data (resource); + uint32_t all_adjustments = (ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X | + ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y); + + if ((constraint_adjustment & ~all_adjustments) != 0) + { + wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + "Invalid constraint action"); + return; + } + + positioner->constraint_adjustment = constraint_adjustment; +} + +static void +zxdg_positioner_v6_set_offset (struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y) +{ + MetaWaylandZxdgPositionerV6 *positioner = wl_resource_get_user_data (resource); + + positioner->offset_x = x; + positioner->offset_y = y; +} + +static const struct zxdg_positioner_v6_interface meta_wayland_zxdg_positioner_v6_interface = { + zxdg_positioner_v6_destroy, + zxdg_positioner_v6_set_size, + zxdg_positioner_v6_set_anchor_rect, + zxdg_positioner_v6_set_anchor, + zxdg_positioner_v6_set_gravity, + zxdg_positioner_v6_set_constraint_adjustment, + zxdg_positioner_v6_set_offset, +}; + +static void +zxdg_positioner_v6_destructor (struct wl_resource *resource) +{ + MetaWaylandZxdgPositionerV6 *positioner = wl_resource_get_user_data (resource); + + g_free (positioner); +} + +static void +zxdg_shell_v6_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandZxdgShellV6Client *shell_client = wl_resource_get_user_data (resource); + + if (shell_client->surfaces || shell_client->surface_constructors) + wl_resource_post_error (resource, ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, + "xdg_shell destroyed before its surfaces"); + + wl_resource_destroy (resource); +} + +static void +zxdg_shell_v6_create_positioner (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + MetaWaylandZxdgPositionerV6 *positioner; + struct wl_resource *positioner_resource; + + positioner = g_new0 (MetaWaylandZxdgPositionerV6, 1); + positioner_resource = wl_resource_create (client, + &zxdg_positioner_v6_interface, + wl_resource_get_version (resource), + id); + wl_resource_set_implementation (positioner_resource, + &meta_wayland_zxdg_positioner_v6_interface, + positioner, + zxdg_positioner_v6_destructor); +} + +static void +zxdg_shell_v6_get_xdg_surface (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource) +{ + MetaWaylandZxdgShellV6Client *shell_client = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandZxdgSurfaceV6 *xdg_surface = NULL; + MetaWaylandZxdgSurfaceV6Constructor *constructor; + + if (surface->role && !META_IS_WAYLAND_ZXDG_SURFACE_V6 (surface->role)) + { + wl_resource_post_error (resource, ZXDG_SHELL_V6_ERROR_ROLE, + "wl_surface@%d already has a different role", + wl_resource_get_id (surface->resource)); + return; + } + + if (surface->role) + xdg_surface = META_WAYLAND_ZXDG_SURFACE_V6 (surface->role); + if (xdg_surface && meta_wayland_zxdg_surface_v6_is_assigned (xdg_surface)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "zxdg_shell_v6::get_xdg_surface already requested"); + return; + } + + if (surface->buffer_ref.buffer) + { + wl_resource_post_error (resource, + ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + "wl_surface@%d already has a buffer committed", + wl_resource_get_id (surface->resource)); + return; + } + + constructor = g_new0 (MetaWaylandZxdgSurfaceV6Constructor, 1); + constructor->surface = surface; + constructor->shell_client = shell_client; + constructor->resource = wl_resource_create (client, + &zxdg_surface_v6_interface, + wl_resource_get_version (resource), + id); + wl_resource_set_implementation (constructor->resource, + &meta_wayland_zxdg_surface_v6_constructor_interface, + constructor, + zxdg_surface_v6_constructor_destructor); + + shell_client->surface_constructors = + g_list_append (shell_client->surface_constructors, constructor); +} + +static void +zxdg_shell_v6_pong (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) +{ + MetaDisplay *display = meta_get_display (); + + meta_display_pong_for_serial (display, serial); +} + +static const struct zxdg_shell_v6_interface meta_wayland_zxdg_shell_v6_interface = { + zxdg_shell_v6_destroy, + zxdg_shell_v6_create_positioner, + zxdg_shell_v6_get_xdg_surface, + zxdg_shell_v6_pong, +}; + +static void +meta_wayland_zxdg_shell_v6_client_destroy (MetaWaylandZxdgShellV6Client *shell_client) +{ + while (shell_client->surface_constructors) + { + MetaWaylandZxdgSurfaceV6Constructor *constructor = + g_list_first (shell_client->surface_constructors)->data; + + wl_resource_destroy (constructor->resource); + } + g_list_free (shell_client->surface_constructors); + + while (shell_client->surfaces) + { + MetaWaylandZxdgSurfaceV6 *xdg_surface = + g_list_first (shell_client->surfaces)->data; + + meta_wayland_zxdg_surface_v6_shell_client_destroyed (xdg_surface); + } + g_list_free (shell_client->surfaces); + + g_free (shell_client); +} + +static void +zxdg_shell_v6_destructor (struct wl_resource *resource) +{ + MetaWaylandZxdgShellV6Client *shell_client = wl_resource_get_user_data (resource); + + meta_wayland_zxdg_shell_v6_client_destroy (shell_client); +} + +static void +bind_zxdg_shell_v6 (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + MetaWaylandZxdgShellV6Client *shell_client; + + shell_client = g_new0 (MetaWaylandZxdgShellV6Client, 1); + + shell_client->resource = wl_resource_create (client, + &zxdg_shell_v6_interface, + version, id); + wl_resource_set_implementation (shell_client->resource, + &meta_wayland_zxdg_shell_v6_interface, + shell_client, zxdg_shell_v6_destructor); +} + +void +meta_wayland_legacy_xdg_shell_init (MetaWaylandCompositor *compositor) +{ + if (wl_global_create (compositor->wayland_display, + &zxdg_shell_v6_interface, + META_ZXDG_SHELL_V6_VERSION, + compositor, bind_zxdg_shell_v6) == NULL) + g_error ("Failed to register a global xdg-shell object"); +} diff --git a/src/wayland/meta-wayland-legacy-xdg-shell.h b/src/wayland/meta-wayland-legacy-xdg-shell.h new file mode 100644 index 000000000..54ddacd50 --- /dev/null +++ b/src/wayland/meta-wayland-legacy-xdg-shell.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013-2015 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_WAYLAND_LEGACY_XDG_SHELL_H +#define META_WAYLAND_LEGACY_XDG_SHELL_H + +#include "wayland/meta-wayland-surface.h" +#include "wayland/meta-wayland-shell-surface.h" + +#define META_TYPE_WAYLAND_ZXDG_SURFACE_V6 (meta_wayland_zxdg_surface_v6_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaWaylandZxdgSurfaceV6, + meta_wayland_zxdg_surface_v6, + META, WAYLAND_ZXDG_SURFACE_V6, + MetaWaylandShellSurface) + +struct _MetaWaylandZxdgSurfaceV6Class +{ + MetaWaylandShellSurfaceClass parent_class; + + void (*shell_client_destroyed) (MetaWaylandZxdgSurfaceV6 *xdg_surface); +}; + +#define META_TYPE_WAYLAND_ZXDG_TOPLEVEL_V6 (meta_wayland_zxdg_toplevel_v6_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandZxdgToplevelV6, + meta_wayland_zxdg_toplevel_v6, + META, WAYLAND_ZXDG_TOPLEVEL_V6, + MetaWaylandZxdgSurfaceV6); + +#define META_TYPE_WAYLAND_ZXDG_POPUP_V6 (meta_wayland_zxdg_popup_v6_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandZxdgPopupV6, + meta_wayland_zxdg_popup_v6, + META, WAYLAND_ZXDG_POPUP_V6, + MetaWaylandZxdgSurfaceV6); + +void meta_wayland_legacy_xdg_shell_init (MetaWaylandCompositor *compositor); + +#endif /* META_WAYLAND_LEGACY_XDG_SHELL_H */ diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 8c41a1078..0fd6237f8 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -43,6 +43,7 @@ #include "meta-wayland-data-device.h" #include "meta-wayland-outputs.h" #include "meta-wayland-xdg-shell.h" +#include "meta-wayland-legacy-xdg-shell.h" #include "meta-wayland-wl-shell.h" #include "meta-wayland-gtk-shell.h" @@ -1199,6 +1200,21 @@ window_position_changed (MetaWindow *window, meta_wayland_surface_update_outputs_recursively (surface); } +void +meta_wayland_surface_create_surface_actor (MetaWaylandSurface *surface) +{ + MetaSurfaceActor *surface_actor; + + surface_actor = meta_surface_actor_wayland_new (surface); + surface->surface_actor = g_object_ref_sink (surface_actor); +} + +void +meta_wayland_surface_clear_surface_actor (MetaWaylandSurface *surface) +{ + g_clear_object (&surface->surface_actor); +} + MetaWaylandSurface * meta_wayland_surface_create (MetaWaylandCompositor *compositor, struct wl_client *client, @@ -1269,6 +1285,7 @@ void meta_wayland_shell_init (MetaWaylandCompositor *compositor) { meta_wayland_xdg_shell_init (compositor); + meta_wayland_legacy_xdg_shell_init (compositor); meta_wayland_wl_shell_init (compositor); meta_wayland_gtk_shell_init (compositor); } diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index e04acb655..05d2a0a24 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -231,6 +231,10 @@ void meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurf void meta_wayland_surface_set_window (MetaWaylandSurface *surface, MetaWindow *window); +void meta_wayland_surface_create_surface_actor (MetaWaylandSurface *surface); + +void meta_wayland_surface_clear_surface_actor (MetaWaylandSurface *surface); + void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface, int new_x, int new_y, diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h index 0f2593bbf..81d37ef0a 100644 --- a/src/wayland/meta-wayland-versions.h +++ b/src/wayland/meta-wayland-versions.h @@ -37,7 +37,8 @@ /* Global/master objects (version exported by wl_registry and negotiated through bind) */ #define META_WL_COMPOSITOR_VERSION 4 #define META_WL_DATA_DEVICE_MANAGER_VERSION 3 -#define META_XDG_SHELL_VERSION 1 +#define META_XDG_WM_BASE_VERSION 1 +#define META_ZXDG_SHELL_V6_VERSION 1 #define META_WL_SHELL_VERSION 1 #define META_WL_SEAT_VERSION 5 #define META_WL_OUTPUT_VERSION 2 diff --git a/src/wayland/meta-wayland-xdg-foreign.c b/src/wayland/meta-wayland-xdg-foreign.c index faf373ee8..cfeb81738 100644 --- a/src/wayland/meta-wayland-xdg-foreign.c +++ b/src/wayland/meta-wayland-xdg-foreign.c @@ -32,6 +32,7 @@ #include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-versions.h" #include "wayland/meta-wayland-xdg-shell.h" +#include "wayland/meta-wayland-legacy-xdg-shell.h" #include "xdg-foreign-unstable-v1-server-protocol.h" @@ -145,6 +146,7 @@ xdg_exporter_export (struct wl_client *client, if (!surface->role || !META_IS_WAYLAND_XDG_SURFACE (surface->role) || + !META_IS_WAYLAND_ZXDG_SURFACE_V6 (surface->role) || !surface->window) { wl_resource_post_error (resource, @@ -254,6 +256,9 @@ is_valid_child (MetaWaylandSurface *surface) if (!META_IS_WAYLAND_XDG_SURFACE (surface->role)) return FALSE; + if (!META_IS_WAYLAND_ZXDG_SURFACE_V6 (surface->role)) + return FALSE; + if (!surface->window) return FALSE; @@ -376,7 +381,9 @@ xdg_importer_import (struct wl_client *client, xdg_imported_destructor); exported = g_hash_table_lookup (foreign->exported_surfaces, handle); - if (!exported || !META_IS_WAYLAND_XDG_SURFACE (exported->surface->role)) + if (!exported || + (!META_IS_WAYLAND_XDG_SURFACE (exported->surface->role) && + !META_IS_WAYLAND_ZXDG_SURFACE_V6 (exported->surface->role))) { zxdg_imported_v1_send_destroyed (resource); return; diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c index fe564531e..cffffa840 100644 --- a/src/wayland/meta-wayland-xdg-shell.c +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -36,7 +36,8 @@ #include "wayland/meta-wayland-surface.h" #include "wayland/meta-wayland-versions.h" #include "wayland/meta-window-wayland.h" -#include "xdg-shell-unstable-v6-server-protocol.h" + +#include "xdg-shell-server-protocol.h" enum { @@ -106,10 +107,12 @@ struct _MetaWaylandXdgPopup struct wl_resource *resource; MetaWaylandSurface *parent_surface; - struct wl_listener parent_destroy_listener; + gulong parent_surface_unmapped_handler_id; MetaWaylandPopup *popup; + gboolean dismissed_by_client; + struct { MetaWaylandSurface *parent_surface; @@ -137,7 +140,7 @@ static MetaPlacementRule meta_wayland_xdg_positioner_to_placement (MetaWaylandXdgPositioner *xdg_positioner); static struct wl_resource * -meta_wayland_xdg_surface_get_shell_resource (MetaWaylandXdgSurface *xdg_surface); +meta_wayland_xdg_surface_get_wm_base_resource (MetaWaylandXdgSurface *xdg_surface); static MetaRectangle meta_wayland_xdg_surface_get_window_geometry (MetaWaylandXdgSurface *xdg_surface); @@ -158,6 +161,12 @@ surface_from_xdg_toplevel_resource (struct wl_resource *resource) return surface_from_xdg_surface_resource (resource); } +static void +meta_wayland_xdg_surface_reset (MetaWaylandXdgSurface *xdg_surface) +{ + META_WAYLAND_XDG_SURFACE_GET_CLASS (xdg_surface)->reset (xdg_surface); +} + static void xdg_toplevel_destructor (struct wl_resource *resource) { @@ -262,13 +271,13 @@ grab_op_for_xdg_toplevel_resize_edge (int edge) { MetaGrabOp op = META_GRAB_OP_WINDOW_BASE; - if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP) + if (edge & XDG_TOPLEVEL_RESIZE_EDGE_TOP) op |= META_GRAB_OP_WINDOW_DIR_NORTH; - if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM) + if (edge & XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM) op |= META_GRAB_OP_WINDOW_DIR_SOUTH; - if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT) + if (edge & XDG_TOPLEVEL_RESIZE_EDGE_LEFT) op |= META_GRAB_OP_WINDOW_DIR_WEST; - if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT) + if (edge & XDG_TOPLEVEL_RESIZE_EDGE_RIGHT) op |= META_GRAB_OP_WINDOW_DIR_EAST; if (op == META_GRAB_OP_WINDOW_BASE) @@ -310,7 +319,7 @@ xdg_toplevel_set_max_size (struct wl_client *client, if (width < 0 || height < 0) { wl_resource_post_error (resource, - ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "invalid negative max size requested %i x %i", width, height); return; @@ -332,7 +341,7 @@ xdg_toplevel_set_min_size (struct wl_client *client, if (width < 0 || height < 0) { wl_resource_post_error (resource, - ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "invalid negative min size requested %i x %i", width, height); return; @@ -373,8 +382,12 @@ xdg_toplevel_set_fullscreen (struct wl_client *client, if (output_resource) { MetaWaylandOutput *output = wl_resource_get_user_data (output_resource); + if (output) - meta_window_move_to_monitor (surface->window, output->logical_monitor->number); + { + meta_window_move_to_monitor (surface->window, + output->logical_monitor->number); + } } meta_window_make_fullscreen (surface->window); @@ -398,7 +411,7 @@ xdg_toplevel_set_minimized (struct wl_client *client, meta_window_minimize (surface->window); } -static const struct zxdg_toplevel_v6_interface meta_wayland_xdg_toplevel_interface = { +static const struct xdg_toplevel_interface meta_wayland_xdg_toplevel_interface = { xdg_toplevel_destroy, xdg_toplevel_set_parent, xdg_toplevel_set_title, @@ -415,20 +428,36 @@ static const struct zxdg_toplevel_v6_interface meta_wayland_xdg_toplevel_interfa xdg_toplevel_set_minimized, }; +static void +meta_wayland_xdg_popup_unmap (MetaWaylandXdgPopup *xdg_popup) +{ + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (xdg_popup); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + g_assert (!xdg_popup->popup); + + if (xdg_popup->parent_surface) + { + g_signal_handler_disconnect (xdg_popup->parent_surface, + xdg_popup->parent_surface_unmapped_handler_id); + xdg_popup->parent_surface = NULL; + } + + meta_wayland_surface_destroy_window (surface); +} + static void xdg_popup_destructor (struct wl_resource *resource) { MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (wl_resource_get_user_data (resource)); - if (xdg_popup->parent_surface) - { - wl_list_remove (&xdg_popup->parent_destroy_listener.link); - xdg_popup->parent_surface = NULL; - } - if (xdg_popup->popup) meta_wayland_popup_dismiss (xdg_popup->popup); + else + meta_wayland_xdg_popup_unmap (xdg_popup); xdg_popup->resource = NULL; } @@ -455,7 +484,7 @@ xdg_popup_grab (struct wl_client *client, if (!parent_surface) { wl_resource_post_error (resource, - ZXDG_POPUP_V6_ERROR_INVALID_GRAB, + XDG_POPUP_ERROR_INVALID_GRAB, "tried to grab after popup was mapped"); return; } @@ -464,27 +493,25 @@ xdg_popup_grab (struct wl_client *client, xdg_popup->setup.grab_serial = serial; } -static const struct zxdg_popup_v6_interface meta_wayland_xdg_popup_interface = { +static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = { xdg_popup_destroy, xdg_popup_grab, }; static void -handle_popup_parent_destroyed (struct wl_listener *listener, - void *data) +on_parent_surface_unmapped (MetaWaylandSurface *parent_surface, + MetaWaylandXdgPopup *xdg_popup) { - MetaWaylandXdgPopup *xdg_popup = - wl_container_of (listener, xdg_popup, parent_destroy_listener); MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_popup); - struct wl_resource *xdg_shell_resource = - meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + struct wl_resource *xdg_wm_base_resource = + meta_wayland_xdg_surface_get_wm_base_resource (xdg_surface); MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (xdg_popup); MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); - wl_resource_post_error (xdg_shell_resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + wl_resource_post_error (xdg_wm_base_resource, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, "destroyed popup not top most popup"); xdg_popup->parent_surface = NULL; @@ -500,22 +527,22 @@ fill_states (struct wl_array *states, if (META_WINDOW_MAXIMIZED (window)) { s = wl_array_add (states, sizeof *s); - *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; + *s = XDG_TOPLEVEL_STATE_MAXIMIZED; } if (meta_window_is_fullscreen (window)) { s = wl_array_add (states, sizeof *s); - *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; + *s = XDG_TOPLEVEL_STATE_FULLSCREEN; } if (meta_grab_op_is_resizing (window->display->grab_op)) { s = wl_array_add (states, sizeof *s); - *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; + *s = XDG_TOPLEVEL_STATE_RESIZING; } if (meta_window_appears_focused (window)) { s = wl_array_add (states, sizeof *s); - *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; + *s = XDG_TOPLEVEL_STATE_ACTIVATED; } } @@ -536,9 +563,9 @@ meta_wayland_xdg_toplevel_send_configure (MetaWaylandXdgToplevel *xdg_toplevel, wl_array_init (&states); fill_states (&states, surface->window); - zxdg_toplevel_v6_send_configure (xdg_toplevel->resource, - new_width, new_height, - &states); + xdg_toplevel_send_configure (xdg_toplevel->resource, + new_width, new_height, + &states); wl_array_release (&states); serial = meta_wayland_xdg_surface_send_configure (xdg_surface); @@ -592,9 +619,17 @@ meta_wayland_xdg_toplevel_commit (MetaWaylandSurfaceRole *surface_role, MetaWaylandSurfaceRoleClass *surface_role_class; MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); - MetaWindow *window = surface->window; + MetaWindow *window; MetaRectangle window_geometry; + if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached) + { + meta_wayland_xdg_surface_reset (xdg_surface); + return; + } + + window = surface->window; + surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_toplevel_parent_class); surface_role_class->commit (surface_role, pending); @@ -608,10 +643,6 @@ meta_wayland_xdg_toplevel_commit (MetaWaylandSurfaceRole *surface_role, if (!pending->newly_attached) return; - /* If the window disappeared the surface is not coming back. */ - if (!window) - return; - if (pending->has_new_geometry) { window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface); @@ -632,17 +663,21 @@ meta_wayland_xdg_toplevel_commit (MetaWaylandSurfaceRole *surface_role, if (is_new_size_hints_valid (window, pending)) { if (pending->has_new_min_size) - meta_window_wayland_set_min_size (window, pending->new_min_width, pending->new_min_height); + meta_window_wayland_set_min_size (window, + pending->new_min_width, + pending->new_min_height); if (pending->has_new_max_size) - meta_window_wayland_set_max_size (window, pending->new_max_width, pending->new_max_height); + meta_window_wayland_set_max_size (window, + pending->new_max_width, + pending->new_max_height); meta_window_recalc_features (window); } else { wl_resource_post_error (surface->resource, - ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "Invalid min/max size"); } @@ -657,6 +692,30 @@ meta_wayland_xdg_toplevel_get_toplevel (MetaWaylandSurfaceRole *surface_role) return meta_wayland_surface_role_get_surface (surface_role); } +static void +meta_wayland_xdg_toplevel_reset (MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandShellSurface *shell_surface = + META_WAYLAND_SHELL_SURFACE (xdg_surface); + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (xdg_surface); + MetaWaylandXdgSurfaceClass *xdg_surface_class = + META_WAYLAND_XDG_SURFACE_CLASS (meta_wayland_xdg_toplevel_parent_class); + MetaWaylandSurface *surface; + MetaWindow *window; + + surface = meta_wayland_surface_role_get_surface (surface_role); + + meta_wayland_surface_destroy_window (surface); + meta_wayland_surface_clear_surface_actor (surface); + + meta_wayland_surface_create_surface_actor (surface); + window = meta_window_wayland_new (meta_get_display (), surface); + meta_wayland_shell_surface_set_window (shell_surface, window); + + xdg_surface_class->reset (xdg_surface); +} + static void meta_wayland_xdg_toplevel_configure (MetaWaylandShellSurface *shell_surface, int new_x, @@ -694,7 +753,7 @@ meta_wayland_xdg_toplevel_close (MetaWaylandShellSurface *shell_surface) MetaWaylandXdgToplevel *xdg_toplevel = META_WAYLAND_XDG_TOPLEVEL (shell_surface); - zxdg_toplevel_v6_send_close (xdg_toplevel->resource); + xdg_toplevel_send_close (xdg_toplevel->resource); } static void @@ -702,8 +761,8 @@ meta_wayland_xdg_toplevel_shell_client_destroyed (MetaWaylandXdgSurface *xdg_sur { MetaWaylandXdgToplevel *xdg_toplevel = META_WAYLAND_XDG_TOPLEVEL (xdg_surface); - struct wl_resource *xdg_shell_resource = - meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + struct wl_resource *xdg_wm_base_resource = + meta_wayland_xdg_surface_get_wm_base_resource (xdg_surface); MetaWaylandXdgSurfaceClass *xdg_surface_class = META_WAYLAND_XDG_SURFACE_CLASS (meta_wayland_xdg_toplevel_parent_class); @@ -711,9 +770,9 @@ meta_wayland_xdg_toplevel_shell_client_destroyed (MetaWaylandXdgSurface *xdg_sur if (xdg_toplevel->resource) { - wl_resource_post_error (xdg_shell_resource, - ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, - "xdg_shell of xdg_toplevel@%d was destroyed", + wl_resource_post_error (xdg_wm_base_resource, + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES, + "xdg_wm_base of xdg_toplevel@%d was destroyed", wl_resource_get_id (xdg_toplevel->resource)); wl_resource_destroy (xdg_toplevel->resource); @@ -758,6 +817,7 @@ meta_wayland_xdg_toplevel_class_init (MetaWaylandXdgToplevelClass *klass) xdg_surface_class = META_WAYLAND_XDG_SURFACE_CLASS (klass); xdg_surface_class->shell_client_destroyed = meta_wayland_xdg_toplevel_shell_client_destroyed; + xdg_surface_class->reset = meta_wayland_xdg_toplevel_reset; } static void @@ -785,8 +845,8 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup) MetaWaylandShellSurface *shell_surface = META_WAYLAND_SHELL_SURFACE (xdg_surface); MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (xdg_popup); - struct wl_resource *xdg_shell_resource = - meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + struct wl_resource *xdg_wm_base_resource = + meta_wayland_xdg_surface_get_wm_base_resource (xdg_surface); MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); MetaWaylandSurface *parent_surface; @@ -805,7 +865,7 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup) if (!parent_surface->window) { - zxdg_popup_v6_send_popup_done (xdg_popup->resource); + xdg_popup_send_popup_done (xdg_popup->resource); return; } @@ -815,24 +875,25 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup) if (!meta_wayland_seat_can_popup (seat, serial)) { - zxdg_popup_v6_send_popup_done (xdg_popup->resource); + xdg_popup_send_popup_done (xdg_popup->resource); return; } top_popup = meta_wayland_pointer_get_top_popup (seat->pointer); if (top_popup && parent_surface != top_popup) { - wl_resource_post_error (xdg_shell_resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + wl_resource_post_error (xdg_wm_base_resource, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, "parent not top most surface"); return; } } xdg_popup->parent_surface = parent_surface; - xdg_popup->parent_destroy_listener.notify = handle_popup_parent_destroyed; - wl_resource_add_destroy_listener (parent_surface->resource, - &xdg_popup->parent_destroy_listener); + xdg_popup->parent_surface_unmapped_handler_id = + g_signal_connect (parent_surface, "unmapped", + G_CALLBACK (on_parent_surface_unmapped), + xdg_popup); window = meta_window_wayland_new (display, surface); meta_wayland_shell_surface_set_window (shell_surface, window); @@ -852,7 +913,7 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup) popup_surface); if (popup == NULL) { - zxdg_popup_v6_send_popup_done (xdg_popup->resource); + xdg_popup_send_popup_done (xdg_popup->resource); meta_wayland_surface_destroy_window (surface); return; } @@ -861,7 +922,7 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup) } else { - /* The keyboard focus semantics for non-grabbing zxdg_shell_v6 popups + /* The keyboard focus semantics for non-grabbing xdg_wm_base popups * is pretty undefined. Same applies for subsurfaces, but in practice, * subsurfaces never receive keyboard focus, so it makes sense to * do the same for non-grabbing popups. @@ -878,6 +939,8 @@ meta_wayland_xdg_popup_commit (MetaWaylandSurfaceRole *surface_role, { MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (surface_role); MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role); + MetaWaylandXdgSurfacePrivate *xdg_surface_priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); MetaWaylandSurfaceRoleClass *surface_role_class; MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); @@ -886,10 +949,24 @@ meta_wayland_xdg_popup_commit (MetaWaylandSurfaceRole *surface_role, if (xdg_popup->setup.parent_surface) finish_popup_setup (xdg_popup); + if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached) + { + meta_wayland_xdg_surface_reset (xdg_surface); + return; + } + surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_popup_parent_class); surface_role_class->commit (surface_role, pending); + if (xdg_popup->dismissed_by_client && surface->buffer_ref.buffer) + { + wl_resource_post_error (xdg_popup->resource, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, + "Can't commit buffer to dismissed popup"); + return; + } + /* If the window disappeared the surface is not coming back. */ if (!surface->window) return; @@ -918,6 +995,23 @@ meta_wayland_xdg_popup_get_toplevel (MetaWaylandSurfaceRole *surface_role) return NULL; } +static void +meta_wayland_xdg_popup_reset (MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (xdg_surface); + MetaWaylandXdgSurfaceClass *xdg_surface_class = + META_WAYLAND_XDG_SURFACE_CLASS (meta_wayland_xdg_popup_parent_class); + + if (xdg_popup->popup) + meta_wayland_popup_dismiss (xdg_popup->popup); + else + meta_wayland_xdg_popup_unmap (xdg_popup); + + xdg_popup->dismissed_by_client = TRUE; + + xdg_surface_class->reset (xdg_surface); +} + static void meta_wayland_xdg_popup_configure (MetaWaylandShellSurface *shell_surface, int new_x, @@ -946,8 +1040,8 @@ meta_wayland_xdg_popup_configure (MetaWaylandShellSurface *shell_surface, geometry_scale = meta_window_wayland_get_geometry_scale (parent_window); x = (new_x - parent_window->rect.x) / geometry_scale; y = (new_y - parent_window->rect.y) / geometry_scale; - zxdg_popup_v6_send_configure (xdg_popup->resource, - x, y, new_width, new_height); + xdg_popup_send_configure (xdg_popup->resource, + x, y, new_width, new_height); meta_wayland_xdg_surface_send_configure (xdg_surface); } @@ -968,8 +1062,8 @@ static void meta_wayland_xdg_popup_shell_client_destroyed (MetaWaylandXdgSurface *xdg_surface) { MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (xdg_surface); - struct wl_resource *xdg_shell_resource = - meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + struct wl_resource *xdg_wm_base_resource = + meta_wayland_xdg_surface_get_wm_base_resource (xdg_surface); MetaWaylandXdgSurfaceClass *xdg_surface_class = META_WAYLAND_XDG_SURFACE_CLASS (meta_wayland_xdg_popup_parent_class); @@ -977,9 +1071,9 @@ meta_wayland_xdg_popup_shell_client_destroyed (MetaWaylandXdgSurface *xdg_surfac if (xdg_popup->resource) { - wl_resource_post_error (xdg_shell_resource, - ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, - "xdg_shell of xdg_popup@%d was destroyed", + wl_resource_post_error (xdg_wm_base_resource, + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES, + "xdg_wm_base of xdg_popup@%d was destroyed", wl_resource_get_id (xdg_popup->resource)); wl_resource_destroy (xdg_popup->resource); @@ -991,7 +1085,7 @@ meta_wayland_xdg_popup_done (MetaWaylandPopupSurface *popup_surface) { MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (popup_surface); - zxdg_popup_v6_send_popup_done (xdg_popup->resource); + xdg_popup_send_popup_done (xdg_popup->resource); } static void @@ -999,8 +1093,8 @@ meta_wayland_xdg_popup_dismiss (MetaWaylandPopupSurface *popup_surface) { MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (popup_surface); MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_popup); - struct wl_resource *xdg_shell_resource = - meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + struct wl_resource *xdg_wm_base_resource = + meta_wayland_xdg_surface_get_wm_base_resource (xdg_surface); MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (xdg_popup); MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); @@ -1009,14 +1103,13 @@ meta_wayland_xdg_popup_dismiss (MetaWaylandPopupSurface *popup_surface) top_popup = meta_wayland_popup_get_top_popup (xdg_popup->popup); if (surface != top_popup) { - wl_resource_post_error (xdg_shell_resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + wl_resource_post_error (xdg_wm_base_resource, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, "destroyed popup not top most popup"); } xdg_popup->popup = NULL; - - meta_wayland_surface_destroy_window (surface); + meta_wayland_xdg_popup_unmap (xdg_popup); } static MetaWaylandSurface * @@ -1073,10 +1166,11 @@ meta_wayland_xdg_popup_class_init (MetaWaylandXdgPopupClass *klass) xdg_surface_class = META_WAYLAND_XDG_SURFACE_CLASS (klass); xdg_surface_class->shell_client_destroyed = meta_wayland_xdg_popup_shell_client_destroyed; + xdg_surface_class->reset = meta_wayland_xdg_popup_reset; } static struct wl_resource * -meta_wayland_xdg_surface_get_shell_resource (MetaWaylandXdgSurface *xdg_surface) +meta_wayland_xdg_surface_get_wm_base_resource (MetaWaylandXdgSurface *xdg_surface) { MetaWaylandXdgSurfacePrivate *priv = meta_wayland_xdg_surface_get_instance_private (xdg_surface); @@ -1112,7 +1206,7 @@ meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface *xdg_surface) display = wl_client_get_display (wl_resource_get_client (priv->resource)); serial = wl_display_next_serial (display); - zxdg_surface_v6_send_configure (priv->resource, serial); + xdg_surface_send_configure (priv->resource, serial); priv->configure_sent = TRUE; @@ -1151,10 +1245,10 @@ xdg_surface_get_toplevel (struct wl_client *client, { MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource); MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); - struct wl_resource *xdg_shell_resource = - meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + struct wl_resource *xdg_wm_base_resource = + meta_wayland_xdg_surface_get_wm_base_resource (xdg_surface); - wl_resource_post_error (xdg_shell_resource, ZXDG_SHELL_V6_ERROR_ROLE, + wl_resource_post_error (xdg_wm_base_resource, XDG_WM_BASE_ERROR_ROLE, "wl_surface@%d already has a role assigned", wl_resource_get_id (surface->resource)); } @@ -1172,7 +1266,7 @@ xdg_surface_get_popup (struct wl_client *client, MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); wl_resource_post_error (priv->shell_client->resource, - ZXDG_SHELL_V6_ERROR_ROLE, + XDG_WM_BASE_ERROR_ROLE, "wl_surface@%d already has a role assigned", wl_resource_get_id (surface->resource)); } @@ -1207,7 +1301,7 @@ xdg_surface_ack_configure (struct wl_client *client, priv->acked_configure_serial.value = serial; } -static const struct zxdg_surface_v6_interface meta_wayland_xdg_surface_interface = { +static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = { xdg_surface_destroy, xdg_surface_get_toplevel, xdg_surface_get_popup, @@ -1227,6 +1321,18 @@ meta_wayland_xdg_surface_finalize (GObject *object) G_OBJECT_CLASS (meta_wayland_xdg_surface_parent_class)->finalize (object); } +static void +meta_wayland_xdg_surface_real_reset (MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); + + priv->first_buffer_attached = FALSE; + priv->configure_sent = FALSE; + priv->geometry = (MetaRectangle) { 0 }; + priv->has_set_geometry = FALSE; +} + static void meta_wayland_xdg_surface_commit (MetaWaylandSurfaceRole *surface_role, MetaWaylandPendingState *pending) @@ -1249,23 +1355,6 @@ meta_wayland_xdg_surface_commit (MetaWaylandSurfaceRole *surface_role, if (!priv->resource) return; - if (surface->buffer_ref.buffer == NULL && priv->first_buffer_attached) - { - /* XDG surfaces can't commit NULL buffers */ - wl_resource_post_error (surface->resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "Cannot commit a NULL buffer to an xdg_surface"); - return; - } - - if (surface->buffer_ref.buffer && !priv->configure_sent) - { - wl_resource_post_error (surface->resource, - ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, - "buffer committed to unconfigured xdg_surface"); - return; - } - if (!window) return; @@ -1305,8 +1394,8 @@ meta_wayland_xdg_surface_assigned (MetaWaylandSurfaceRole *surface_role) meta_wayland_xdg_surface_get_instance_private (xdg_surface); MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); - struct wl_resource *xdg_shell_resource = - meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + struct wl_resource *xdg_wm_base_resource = + meta_wayland_xdg_surface_get_wm_base_resource (xdg_surface); MetaWaylandSurfaceRoleClass *surface_role_class; priv->configure_sent = FALSE; @@ -1314,8 +1403,8 @@ meta_wayland_xdg_surface_assigned (MetaWaylandSurfaceRole *surface_role) if (surface->buffer_ref.buffer) { - wl_resource_post_error (xdg_shell_resource, - ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + wl_resource_post_error (xdg_wm_base_resource, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "wl_surface@%d already has a buffer committed", wl_resource_get_id (surface->resource)); return; @@ -1334,7 +1423,7 @@ meta_wayland_xdg_surface_ping (MetaWaylandShellSurface *shell_surface, MetaWaylandXdgSurfacePrivate *priv = meta_wayland_xdg_surface_get_instance_private (xdg_surface); - zxdg_shell_v6_send_ping (priv->shell_client->resource, serial); + xdg_wm_base_send_ping (priv->shell_client->resource, serial); } static void @@ -1346,8 +1435,8 @@ meta_wayland_xdg_surface_real_shell_client_destroyed (MetaWaylandXdgSurface *xdg if (priv->resource) { wl_resource_post_error (priv->shell_client->resource, - ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, - "xdg_shell of xdg_surface@%d was destroyed", + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES, + "xdg_wm_base of xdg_surface@%d was destroyed", wl_resource_get_id (priv->resource)); wl_resource_destroy (priv->resource); @@ -1431,6 +1520,7 @@ meta_wayland_xdg_surface_class_init (MetaWaylandXdgSurfaceClass *klass) klass->shell_client_destroyed = meta_wayland_xdg_surface_real_shell_client_destroyed; + klass->reset = meta_wayland_xdg_surface_real_reset; pspec = g_param_spec_pointer ("shell-client", "MetaWaylandXdgShellClient", @@ -1482,7 +1572,7 @@ xdg_surface_constructor_destroy (struct wl_client *client, struct wl_resource *resource) { wl_resource_post_error (resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "xdg_surface destroyed before constructed"); wl_resource_destroy (resource); } @@ -1508,7 +1598,7 @@ xdg_surface_constructor_get_toplevel (struct wl_client *client, "xdg-surface-resource", xdg_surface_resource, NULL)) { - wl_resource_post_error (resource, ZXDG_SHELL_V6_ERROR_ROLE, + wl_resource_post_error (resource, XDG_WM_BASE_ERROR_ROLE, "wl_surface@%d already has a different role", wl_resource_get_id (surface->resource)); return; @@ -1516,7 +1606,7 @@ xdg_surface_constructor_get_toplevel (struct wl_client *client, xdg_toplevel = META_WAYLAND_XDG_TOPLEVEL (surface->role); xdg_toplevel->resource = wl_resource_create (client, - &zxdg_toplevel_v6_interface, + &xdg_toplevel_interface, wl_resource_get_version (resource), id); wl_resource_set_implementation (xdg_toplevel->resource, @@ -1543,7 +1633,7 @@ xdg_surface_constructor_get_popup (struct wl_client *client, wl_resource_get_user_data (resource); MetaWaylandXdgShellClient *shell_client = constructor->shell_client; MetaWaylandSurface *surface = constructor->surface; - struct wl_resource *xdg_shell_resource = constructor->shell_client->resource; + struct wl_resource *xdg_wm_base_resource = constructor->shell_client->resource; struct wl_resource *xdg_surface_resource = constructor->resource; MetaWaylandSurface *parent_surface = surface_from_xdg_surface_resource (parent_resource); @@ -1557,7 +1647,7 @@ xdg_surface_constructor_get_popup (struct wl_client *client, "xdg-surface-resource", xdg_surface_resource, NULL)) { - wl_resource_post_error (xdg_shell_resource, ZXDG_SHELL_V6_ERROR_ROLE, + wl_resource_post_error (xdg_wm_base_resource, XDG_WM_BASE_ERROR_ROLE, "wl_surface@%d already has a different role", wl_resource_get_id (surface->resource)); return; @@ -1565,15 +1655,16 @@ xdg_surface_constructor_get_popup (struct wl_client *client, if (!META_IS_WAYLAND_XDG_SURFACE (parent_surface->role)) { - wl_resource_post_error (xdg_shell_resource, - ZXDG_SHELL_V6_ERROR_INVALID_POPUP_PARENT, + wl_resource_post_error (xdg_wm_base_resource, + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT, "Invalid popup parent role"); return; } xdg_popup = META_WAYLAND_XDG_POPUP (surface->role); + xdg_popup->resource = wl_resource_create (client, - &zxdg_popup_v6_interface, + &xdg_popup_interface, wl_resource_get_version (resource), id); wl_resource_set_implementation (xdg_popup->resource, @@ -1599,7 +1690,7 @@ xdg_surface_constructor_set_window_geometry (struct wl_client *client, int32_t height) { wl_resource_post_error (resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "xdg_surface::set_window_geometry called before constructed"); } @@ -1609,11 +1700,11 @@ xdg_surface_constructor_ack_configure (struct wl_client *client, uint32_t serial) { wl_resource_post_error (resource, - ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "xdg_surface::ack_configure called before constructed"); } -static const struct zxdg_surface_v6_interface meta_wayland_xdg_surface_constructor_interface = { +static const struct xdg_surface_interface meta_wayland_xdg_surface_constructor_interface = { xdg_surface_constructor_destroy, xdg_surface_constructor_get_toplevel, xdg_surface_constructor_get_popup, @@ -1634,13 +1725,69 @@ xdg_surface_constructor_destructor (struct wl_resource *resource) g_free (constructor); } +static MetaPlacementAnchor +positioner_anchor_to_placement_anchor (uint32_t anchor) +{ + switch (anchor) + { + case XDG_POSITIONER_ANCHOR_NONE: + return META_PLACEMENT_ANCHOR_NONE; + case XDG_POSITIONER_ANCHOR_TOP: + return META_PLACEMENT_ANCHOR_TOP; + case XDG_POSITIONER_ANCHOR_BOTTOM: + return META_PLACEMENT_ANCHOR_BOTTOM; + case XDG_POSITIONER_ANCHOR_LEFT: + return META_PLACEMENT_ANCHOR_LEFT; + case XDG_POSITIONER_ANCHOR_RIGHT: + return META_PLACEMENT_ANCHOR_RIGHT; + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + return (META_PLACEMENT_ANCHOR_TOP | META_PLACEMENT_ANCHOR_LEFT); + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + return (META_PLACEMENT_ANCHOR_BOTTOM | META_PLACEMENT_ANCHOR_LEFT); + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + return (META_PLACEMENT_ANCHOR_TOP | META_PLACEMENT_ANCHOR_RIGHT); + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + return (META_PLACEMENT_ANCHOR_BOTTOM | META_PLACEMENT_ANCHOR_RIGHT); + default: + g_assert_not_reached (); + } +} + +static MetaPlacementGravity +positioner_gravity_to_placement_gravity (uint32_t gravity) +{ + switch (gravity) + { + case XDG_POSITIONER_GRAVITY_NONE: + return META_PLACEMENT_GRAVITY_NONE; + case XDG_POSITIONER_GRAVITY_TOP: + return META_PLACEMENT_GRAVITY_TOP; + case XDG_POSITIONER_GRAVITY_BOTTOM: + return META_PLACEMENT_GRAVITY_BOTTOM; + case XDG_POSITIONER_GRAVITY_LEFT: + return META_PLACEMENT_GRAVITY_LEFT; + case XDG_POSITIONER_GRAVITY_RIGHT: + return META_PLACEMENT_GRAVITY_RIGHT; + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + return (META_PLACEMENT_GRAVITY_TOP | META_PLACEMENT_GRAVITY_LEFT); + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + return (META_PLACEMENT_GRAVITY_BOTTOM | META_PLACEMENT_GRAVITY_LEFT); + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + return (META_PLACEMENT_GRAVITY_TOP | META_PLACEMENT_GRAVITY_RIGHT); + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + return (META_PLACEMENT_GRAVITY_BOTTOM | META_PLACEMENT_GRAVITY_RIGHT); + default: + g_assert_not_reached (); + } +} + static MetaPlacementRule meta_wayland_xdg_positioner_to_placement (MetaWaylandXdgPositioner *xdg_positioner) { return (MetaPlacementRule) { .anchor_rect = xdg_positioner->anchor_rect, - .gravity = xdg_positioner->gravity, - .anchor = xdg_positioner->anchor, + .gravity = positioner_gravity_to_placement_gravity (xdg_positioner->gravity), + .anchor = positioner_anchor_to_placement_anchor (xdg_positioner->anchor), .constraint_adjustment = xdg_positioner->constraint_adjustment, .offset_x = xdg_positioner->offset_x, .offset_y = xdg_positioner->offset_y, @@ -1666,7 +1813,7 @@ xdg_positioner_set_size (struct wl_client *client, if (width <= 0 || height <= 0) { - wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + wl_resource_post_error (resource, XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid size"); return; } @@ -1687,7 +1834,7 @@ xdg_positioner_set_anchor_rect (struct wl_client *client, if (width <= 0 || height <= 0) { - wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + wl_resource_post_error (resource, XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid anchor rectangle size"); return; } @@ -1707,12 +1854,9 @@ xdg_positioner_set_anchor (struct wl_client *client, { MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource); - if ((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT && - anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) || - (anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP && - anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) + if (anchor > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) { - wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + wl_resource_post_error (resource, XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid anchor"); return; } @@ -1727,12 +1871,9 @@ xdg_positioner_set_gravity (struct wl_client *client, { MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource); - if ((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT && - gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT) || - (gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP && - gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) + if (gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT) { - wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + wl_resource_post_error (resource, XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid gravity"); return; } @@ -1746,16 +1887,16 @@ xdg_positioner_set_constraint_adjustment (struct wl_client *client, uint32_t constraint_adjustment) { MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource); - uint32_t all_adjustments = (ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X | - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X | - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y | - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y | - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X | - ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y); + uint32_t all_adjustments = (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y); if ((constraint_adjustment & ~all_adjustments) != 0) { - wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + wl_resource_post_error (resource, XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid constraint action"); return; } @@ -1775,7 +1916,7 @@ xdg_positioner_set_offset (struct wl_client *client, positioner->offset_y = y; } -static const struct zxdg_positioner_v6_interface meta_wayland_xdg_positioner_interface = { +static const struct xdg_positioner_interface meta_wayland_xdg_positioner_interface = { xdg_positioner_destroy, xdg_positioner_set_size, xdg_positioner_set_anchor_rect, @@ -1794,29 +1935,29 @@ xdg_positioner_destructor (struct wl_resource *resource) } static void -xdg_shell_destroy (struct wl_client *client, - struct wl_resource *resource) +xdg_wm_base_destroy (struct wl_client *client, + struct wl_resource *resource) { MetaWaylandXdgShellClient *shell_client = wl_resource_get_user_data (resource); if (shell_client->surfaces || shell_client->surface_constructors) - wl_resource_post_error (resource, ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, - "xdg_shell destroyed before its surfaces"); + wl_resource_post_error (resource, XDG_WM_BASE_ERROR_DEFUNCT_SURFACES, + "xdg_wm_base destroyed before its surfaces"); wl_resource_destroy (resource); } static void -xdg_shell_create_positioner (struct wl_client *client, - struct wl_resource *resource, - uint32_t id) +xdg_wm_base_create_positioner (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) { MetaWaylandXdgPositioner *positioner; struct wl_resource *positioner_resource; positioner = g_new0 (MetaWaylandXdgPositioner, 1); positioner_resource = wl_resource_create (client, - &zxdg_positioner_v6_interface, + &xdg_positioner_interface, wl_resource_get_version (resource), id); wl_resource_set_implementation (positioner_resource, @@ -1826,10 +1967,10 @@ xdg_shell_create_positioner (struct wl_client *client, } static void -xdg_shell_get_xdg_surface (struct wl_client *client, - struct wl_resource *resource, - uint32_t id, - struct wl_resource *surface_resource) +xdg_wm_base_get_xdg_surface (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource) { MetaWaylandXdgShellClient *shell_client = wl_resource_get_user_data (resource); MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); @@ -1837,7 +1978,7 @@ xdg_shell_get_xdg_surface (struct wl_client *client, if (surface->role && !META_IS_WAYLAND_XDG_SURFACE (surface->role)) { - wl_resource_post_error (resource, ZXDG_SHELL_V6_ERROR_ROLE, + wl_resource_post_error (resource, XDG_WM_BASE_ERROR_ROLE, "wl_surface@%d already has a different role", wl_resource_get_id (surface->resource)); return; @@ -1847,15 +1988,15 @@ xdg_shell_get_xdg_surface (struct wl_client *client, meta_wayland_xdg_surface_is_assigned (META_WAYLAND_XDG_SURFACE (surface->role))) { wl_resource_post_error (surface_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "xdg_shell::get_xdg_surface already requested"); + XDG_WM_BASE_ERROR_ROLE, + "xdg_wm_base::get_xdg_surface already requested"); return; } if (surface->buffer_ref.buffer) { wl_resource_post_error (resource, - ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, "wl_surface@%d already has a buffer committed", wl_resource_get_id (surface->resource)); return; @@ -1865,7 +2006,7 @@ xdg_shell_get_xdg_surface (struct wl_client *client, constructor->surface = surface; constructor->shell_client = shell_client; constructor->resource = wl_resource_create (client, - &zxdg_surface_v6_interface, + &xdg_surface_interface, wl_resource_get_version (resource), id); wl_resource_set_implementation (constructor->resource, @@ -1878,27 +2019,25 @@ xdg_shell_get_xdg_surface (struct wl_client *client, } static void -xdg_shell_pong (struct wl_client *client, - struct wl_resource *resource, - uint32_t serial) +xdg_wm_base_pong (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) { MetaDisplay *display = meta_get_display (); meta_display_pong_for_serial (display, serial); } -static const struct zxdg_shell_v6_interface meta_wayland_xdg_shell_interface = { - xdg_shell_destroy, - xdg_shell_create_positioner, - xdg_shell_get_xdg_surface, - xdg_shell_pong, +static const struct xdg_wm_base_interface meta_wayland_xdg_wm_base_interface = { + xdg_wm_base_destroy, + xdg_wm_base_create_positioner, + xdg_wm_base_get_xdg_surface, + xdg_wm_base_pong, }; static void -xdg_shell_destructor (struct wl_resource *resource) +meta_wayland_xdg_shell_client_destroy (MetaWaylandXdgShellClient *shell_client) { - MetaWaylandXdgShellClient *shell_client = wl_resource_get_user_data (resource); - while (shell_client->surface_constructors) { MetaWaylandXdgSurfaceConstructor *constructor = @@ -1921,29 +2060,38 @@ xdg_shell_destructor (struct wl_resource *resource) } static void -bind_xdg_shell (struct wl_client *client, - void *data, - uint32_t version, - uint32_t id) +xdg_wm_base_destructor (struct wl_resource *resource) +{ + MetaWaylandXdgShellClient *shell_client = + wl_resource_get_user_data (resource); + + meta_wayland_xdg_shell_client_destroy (shell_client); +} + +static void +bind_xdg_wm_base (struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) { MetaWaylandXdgShellClient *shell_client; shell_client = g_new0 (MetaWaylandXdgShellClient, 1); shell_client->resource = wl_resource_create (client, - &zxdg_shell_v6_interface, + &xdg_wm_base_interface, version, id); wl_resource_set_implementation (shell_client->resource, - &meta_wayland_xdg_shell_interface, - shell_client, xdg_shell_destructor); + &meta_wayland_xdg_wm_base_interface, + shell_client, xdg_wm_base_destructor); } void meta_wayland_xdg_shell_init (MetaWaylandCompositor *compositor) { if (wl_global_create (compositor->wayland_display, - &zxdg_shell_v6_interface, - META_XDG_SHELL_VERSION, - compositor, bind_xdg_shell) == NULL) + &xdg_wm_base_interface, + META_XDG_WM_BASE_VERSION, + compositor, bind_xdg_wm_base) == NULL) g_error ("Failed to register a global xdg-shell object"); } diff --git a/src/wayland/meta-wayland-xdg-shell.h b/src/wayland/meta-wayland-xdg-shell.h index aa36a94c2..f90e29bea 100644 --- a/src/wayland/meta-wayland-xdg-shell.h +++ b/src/wayland/meta-wayland-xdg-shell.h @@ -33,6 +33,7 @@ struct _MetaWaylandXdgSurfaceClass MetaWaylandShellSurfaceClass parent_class; void (*shell_client_destroyed) (MetaWaylandXdgSurface *xdg_surface); + void (*reset) (MetaWaylandXdgSurface *xdg_surface); }; #define META_TYPE_WAYLAND_XDG_TOPLEVEL (meta_wayland_xdg_toplevel_get_type ())