diff options
author | Jonas Ådahl <jadahl@gmail.com> | 2016-07-01 16:30:14 +0800 |
---|---|---|
committer | Jonas Ådahl <jadahl@gmail.com> | 2016-08-25 12:19:40 +0800 |
commit | ef3e036b45facfa8aa755eadd289ae8ab23ced5b (patch) | |
tree | 71026597091b1e1ddb3d679849ea2bd1279f18f3 | |
parent | 24c3844246e46ec1c89496e87491f98a67767529 (diff) | |
download | mutter-ef3e036b45facfa8aa755eadd289ae8ab23ced5b.tar.gz |
wayland/xdg-shell: Port to unstable v6
Port the xdg_shell implementation to use the unstable v6 protocol. This
includes:
- making xdg_surface a generic base interface for xdg_shell surface
roles
- create a xdg_toplevel role replacing the old xdg_surface
- change the xdg_opup role to be based on xdg_surface
- make xdg_popup not grab by default
- add support for xdg_positioner
https://bugzilla.gnome.org/show_bug.cgi?id=769936
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/wayland/meta-wayland-xdg-shell.c | 1551 | ||||
-rw-r--r-- | src/wayland/meta-wayland-xdg-shell.h | 23 |
4 files changed, 1220 insertions, 360 deletions
diff --git a/configure.ac b/configure.ac index b13090ba7..9fc98685a 100644 --- a/configure.ac +++ b/configure.ac @@ -272,7 +272,7 @@ AS_IF([test "$have_wayland" = "yes"], [ AC_SUBST([WAYLAND_SCANNER]) AC_DEFINE([HAVE_WAYLAND],[1],[Define if you want to enable Wayland support]) - PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.6], + PKG_CHECK_MODULES(WAYLAND_PROTOCOLS, [wayland-protocols >= 1.7], [ac_wayland_protocols_pkgdatadir=`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`]) AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, $ac_wayland_protocols_pkgdatadir) ]) diff --git a/src/Makefile.am b/src/Makefile.am index e6b8bf3f8..6299702a2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -61,8 +61,8 @@ mutter_built_sources += \ gtk-shell-server-protocol.h \ gtk-primary-selection-protocol.c \ gtk-primary-selection-server-protocol.h \ - xdg-shell-unstable-v5-protocol.c \ - xdg-shell-unstable-v5-server-protocol.h \ + xdg-shell-unstable-v6-protocol.c \ + xdg-shell-unstable-v6-server-protocol.h \ relative-pointer-unstable-v1-protocol.c \ relative-pointer-unstable-v1-server-protocol.h \ pointer-constraints-unstable-v1-protocol.c \ diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c index 6a7441da0..e8c56bb85 100644 --- a/src/wayland/meta-wayland-xdg-shell.c +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -33,33 +33,87 @@ #include "wayland/meta-wayland-surface.h" #include "wayland/meta-wayland-versions.h" #include "wayland/meta-window-wayland.h" -#include "xdg-shell-unstable-v5-server-protocol.h" +#include "xdg-shell-unstable-v6-server-protocol.h" -struct _MetaWaylandXdgSurface +enum { - MetaWaylandSurfaceRoleShellSurface parent; + XDG_SURFACE_PROP_0, + XDG_SURFACE_PROP_SHELL_CLIENT, + XDG_SURFACE_PROP_RESOURCE, +}; + +typedef struct _MetaWaylandXdgShellClient +{ + struct wl_resource *resource; + GList *surfaces; + GList *surface_constructors; +} MetaWaylandXdgShellClient; + +typedef struct _MetaWaylandXdgPositioner +{ + 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; +} MetaWaylandXdgPositioner; + +typedef struct _MetaWaylandXdgSurfaceConstructor +{ + MetaWaylandSurface *surface; + struct wl_resource *resource; + MetaWaylandXdgShellClient *shell_client; +} MetaWaylandXdgSurfaceConstructor; + +typedef struct _MetaWaylandXdgSurfacePrivate +{ struct wl_resource *resource; - struct wl_resource *xdg_shell_resource; + MetaWaylandXdgShellClient *shell_client; MetaWaylandSerial acked_configure_serial; - gboolean has_set_geometry; + MetaRectangle geometry; + + guint configure_sent : 1; + guint first_buffer_attached : 1; + guint has_set_geometry : 1; +} MetaWaylandXdgSurfacePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandXdgSurface, + meta_wayland_xdg_surface, + META_TYPE_WAYLAND_SURFACE_ROLE_SHELL_SURFACE); + +struct _MetaWaylandXdgToplevel +{ + MetaWaylandXdgSurface parent; + + struct wl_resource *resource; }; -G_DEFINE_TYPE (MetaWaylandXdgSurface, - meta_wayland_xdg_surface, - META_TYPE_WAYLAND_SURFACE_ROLE_SHELL_SURFACE); +G_DEFINE_TYPE (MetaWaylandXdgToplevel, + meta_wayland_xdg_toplevel, + META_TYPE_WAYLAND_XDG_SURFACE); struct _MetaWaylandXdgPopup { - MetaWaylandSurfaceRoleShellSurface parent; + MetaWaylandXdgSurface parent; struct wl_resource *resource; - struct wl_resource *xdg_shell_resource; MetaWaylandSurface *parent_surface; struct wl_listener parent_destroy_listener; MetaWaylandPopup *popup; + + struct { + MetaWaylandSurface *parent_surface; + MetaPlacementRule placement_rule; + + MetaWaylandSeat *grab_seat; + uint32_t grab_serial; + } setup; }; static void @@ -67,55 +121,58 @@ popup_surface_iface_init (MetaWaylandPopupSurfaceInterface *iface); G_DEFINE_TYPE_WITH_CODE (MetaWaylandXdgPopup, meta_wayland_xdg_popup, - META_TYPE_WAYLAND_SURFACE_ROLE_SHELL_SURFACE, + META_TYPE_WAYLAND_XDG_SURFACE, G_IMPLEMENT_INTERFACE (META_TYPE_WAYLAND_POPUP_SURFACE, popup_surface_iface_init)); +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); + +static MetaRectangle +meta_wayland_xdg_surface_get_window_geometry (MetaWaylandXdgSurface *xdg_surface); + +static uint32_t +meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface *xdg_surface); + static MetaWaylandSurface * surface_from_xdg_surface_resource (struct wl_resource *resource) { - MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource); - MetaWaylandSurfaceRole *surface_role = - META_WAYLAND_SURFACE_ROLE (xdg_surface); - + MetaWaylandSurfaceRole *surface_role = wl_resource_get_user_data (resource); return meta_wayland_surface_role_get_surface (surface_role); } static MetaWaylandSurface * -surface_from_xdg_popup_resource (struct wl_resource *resource) +surface_from_xdg_toplevel_resource (struct wl_resource *resource) { - MetaWaylandXdgPopup *xdg_popup = wl_resource_get_user_data (resource); - MetaWaylandSurfaceRole *surface_role = - META_WAYLAND_SURFACE_ROLE (xdg_popup); - - return meta_wayland_surface_role_get_surface (surface_role); + return surface_from_xdg_surface_resource (resource); } static void -xdg_surface_destructor (struct wl_resource *resource) +xdg_toplevel_destructor (struct wl_resource *resource) { - MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource); - MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandXdgToplevel *xdg_toplevel = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); - meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, - surface); meta_wayland_surface_destroy_window (surface); - xdg_surface->resource = NULL; + xdg_toplevel->resource = NULL; } static void -xdg_surface_destroy (struct wl_client *client, - struct wl_resource *resource) +xdg_toplevel_destroy (struct wl_client *client, + struct wl_resource *resource) { wl_resource_destroy (resource); } static void -xdg_surface_set_parent (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *parent_resource) +xdg_toplevel_set_parent (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent_resource) { - MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); MetaWindow *transient_for = NULL; if (parent_resource) @@ -130,11 +187,11 @@ xdg_surface_set_parent (struct wl_client *client, } static void -xdg_surface_set_title (struct wl_client *client, - struct wl_resource *resource, - const char *title) +xdg_toplevel_set_title (struct wl_client *client, + struct wl_resource *resource, + const char *title) { - MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); if (!g_utf8_validate (title, -1, NULL)) title = ""; @@ -143,11 +200,11 @@ xdg_surface_set_title (struct wl_client *client, } static void -xdg_surface_set_app_id (struct wl_client *client, - struct wl_resource *resource, - const char *app_id) +xdg_toplevel_set_app_id (struct wl_client *client, + struct wl_resource *resource, + const char *app_id) { - MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); if (!g_utf8_validate (app_id, -1, NULL)) app_id = ""; @@ -156,15 +213,15 @@ xdg_surface_set_app_id (struct wl_client *client, } static void -xdg_surface_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) +xdg_toplevel_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_surface_resource (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); if (!meta_wayland_seat_get_grab_info (seat, surface, serial, FALSE, NULL, NULL)) return; @@ -175,13 +232,13 @@ xdg_surface_show_window_menu (struct wl_client *client, } static void -xdg_surface_move (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *seat_resource, - guint32 serial) +xdg_toplevel_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_surface_resource (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)) @@ -191,17 +248,17 @@ xdg_surface_move (struct wl_client *client, } static MetaGrabOp -grab_op_for_xdg_surface_resize_edge (int edge) +grab_op_for_xdg_toplevel_resize_edge (int edge) { MetaGrabOp op = META_GRAB_OP_WINDOW_BASE; - if (edge & XDG_SURFACE_RESIZE_EDGE_TOP) + if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP) op |= META_GRAB_OP_WINDOW_DIR_NORTH; - if (edge & XDG_SURFACE_RESIZE_EDGE_BOTTOM) + if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM) op |= META_GRAB_OP_WINDOW_DIR_SOUTH; - if (edge & XDG_SURFACE_RESIZE_EDGE_LEFT) + if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT) op |= META_GRAB_OP_WINDOW_DIR_WEST; - if (edge & XDG_SURFACE_RESIZE_EDGE_RIGHT) + if (edge & ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT) op |= META_GRAB_OP_WINDOW_DIR_EAST; if (op == META_GRAB_OP_WINDOW_BASE) @@ -214,124 +271,111 @@ grab_op_for_xdg_surface_resize_edge (int edge) } static void -xdg_surface_resize (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *seat_resource, - guint32 serial, - guint32 edges) +xdg_toplevel_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_surface_resource (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_surface_resize_edge (edges); + grab_op = grab_op_for_xdg_toplevel_resize_edge (edges); meta_wayland_surface_begin_grab_op (surface, seat, grab_op, x, y); } static void -xdg_surface_ack_configure (struct wl_client *client, +xdg_toplevel_set_max_size (struct wl_client *client, struct wl_resource *resource, - uint32_t serial) + int32_t width, + int32_t height) { - MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource); - - xdg_surface->acked_configure_serial.set = TRUE; - xdg_surface->acked_configure_serial.value = serial; + /* TODO */ } static void -xdg_surface_set_window_geometry (struct wl_client *client, - struct wl_resource *resource, - int32_t x, - int32_t y, - int32_t width, - int32_t height) +xdg_toplevel_set_min_size (struct wl_client *client, + struct wl_resource *resource, + 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; + /* TODO */ } static void -xdg_surface_set_maximized (struct wl_client *client, - struct wl_resource *resource) +xdg_toplevel_set_maximized (struct wl_client *client, + struct wl_resource *resource) { - MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); } static void -xdg_surface_unset_maximized (struct wl_client *client, - struct wl_resource *resource) +xdg_toplevel_unset_maximized (struct wl_client *client, + struct wl_resource *resource) { - MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH); } static void -xdg_surface_set_fullscreen (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *output_resource) +xdg_toplevel_set_fullscreen (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output_resource) { - MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); meta_window_make_fullscreen (surface->window); } static void -xdg_surface_unset_fullscreen (struct wl_client *client, - struct wl_resource *resource) +xdg_toplevel_unset_fullscreen (struct wl_client *client, + struct wl_resource *resource) { - MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); meta_window_unmake_fullscreen (surface->window); } static void -xdg_surface_set_minimized (struct wl_client *client, - struct wl_resource *resource) +xdg_toplevel_set_minimized (struct wl_client *client, + struct wl_resource *resource) { - MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource); meta_window_minimize (surface->window); } -static const struct xdg_surface_interface meta_wayland_xdg_surface_interface = { - xdg_surface_destroy, - xdg_surface_set_parent, - xdg_surface_set_title, - xdg_surface_set_app_id, - xdg_surface_show_window_menu, - xdg_surface_move, - xdg_surface_resize, - xdg_surface_ack_configure, - xdg_surface_set_window_geometry, - xdg_surface_set_maximized, - xdg_surface_unset_maximized, - xdg_surface_set_fullscreen, - xdg_surface_unset_fullscreen, - xdg_surface_set_minimized, +static const struct zxdg_toplevel_v6_interface meta_wayland_xdg_toplevel_interface = { + xdg_toplevel_destroy, + xdg_toplevel_set_parent, + xdg_toplevel_set_title, + xdg_toplevel_set_app_id, + xdg_toplevel_show_window_menu, + xdg_toplevel_move, + xdg_toplevel_resize, + xdg_toplevel_set_max_size, + xdg_toplevel_set_min_size, + xdg_toplevel_set_maximized, + xdg_toplevel_unset_maximized, + xdg_toplevel_set_fullscreen, + xdg_toplevel_unset_fullscreen, + xdg_toplevel_set_minimized, }; static void xdg_popup_destructor (struct wl_resource *resource) { - MetaWaylandSurface *surface = surface_from_xdg_popup_resource (resource); MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (wl_resource_get_user_data (resource)); - meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, - surface); if (xdg_popup->parent_surface) { wl_list_remove (&xdg_popup->parent_destroy_listener.link); @@ -345,14 +389,55 @@ xdg_popup_destructor (struct wl_resource *resource) } static void -xdg_popup_destroy (struct wl_client *client, +xdg_popup_destroy (struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy (resource); } -static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = { +static void +xdg_popup_grab (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial) +{ + MetaWaylandXdgPopup *xdg_popup = + META_WAYLAND_XDG_POPUP (wl_resource_get_user_data (resource)); + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *parent_surface; + MetaWaylandSurface *top_popup; + + 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; + } + + top_popup = meta_wayland_pointer_get_top_popup (&seat->pointer); + if ((top_popup == NULL && + !META_IS_WAYLAND_XDG_SURFACE (parent_surface->role)) || + (top_popup != NULL && parent_surface != top_popup)) + { + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_popup); + struct wl_resource *xdg_shell_resource = + meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + + wl_resource_post_error (xdg_shell_resource, + ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + "parent not top most surface"); + return; + } + + xdg_popup->setup.grab_seat = seat; + xdg_popup->setup.grab_serial = serial; +} + +static const struct zxdg_popup_v6_interface meta_wayland_xdg_popup_interface = { xdg_popup_destroy, + xdg_popup_grab, }; static void @@ -361,13 +446,16 @@ handle_popup_parent_destroyed (struct wl_listener *listener, { 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); MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (xdg_popup); MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); - wl_resource_post_error (xdg_popup->xdg_shell_resource, - XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, + 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; @@ -382,46 +470,77 @@ fill_states (struct wl_array *states, MetaWindow *window) if (META_WINDOW_MAXIMIZED (window)) { s = wl_array_add (states, sizeof *s); - *s = XDG_SURFACE_STATE_MAXIMIZED; + *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; } if (meta_window_is_fullscreen (window)) { s = wl_array_add (states, sizeof *s); - *s = XDG_SURFACE_STATE_FULLSCREEN; + *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; } if (meta_grab_op_is_resizing (window->display->grab_op)) { s = wl_array_add (states, sizeof *s); - *s = XDG_SURFACE_STATE_RESIZING; + *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; } if (meta_window_appears_focused (window)) { s = wl_array_add (states, sizeof *s); - *s = XDG_SURFACE_STATE_ACTIVATED; + *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; } } static void -xdg_surface_role_commit (MetaWaylandSurfaceRole *surface_role, - MetaWaylandPendingState *pending) +meta_wayland_xdg_toplevel_send_configure (MetaWaylandXdgToplevel *xdg_toplevel, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial) { - MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role); + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (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_xdg_surface_send_configure (xdg_surface); + + if (sent_serial) + { + sent_serial->set = TRUE; + sent_serial->value = serial; + } +} + +static void +xdg_toplevel_role_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandPendingState *pending) +{ + MetaWaylandXdgToplevel *xdg_toplevel = META_WAYLAND_XDG_TOPLEVEL (surface_role); + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_toplevel); + 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); MetaWindow *window = surface->window; - MetaRectangle geom = { 0 }; + MetaRectangle window_geometry; surface_role_class = - META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_surface_parent_class); + META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_toplevel_parent_class); surface_role_class->commit (surface_role, pending); - if (surface->buffer_ref.buffer == NULL) + if (!xdg_surface_priv->configure_sent) { - /* 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"); + meta_wayland_xdg_toplevel_send_configure (xdg_toplevel, 0, 0, NULL); return; } @@ -432,182 +551,225 @@ xdg_surface_role_commit (MetaWaylandSurfaceRole *surface_role, if (!window) return; - if (pending->has_new_geometry) - { - /* If we have new geometry, use it. */ - geom = pending->new_geometry; - xdg_surface->has_set_geometry = TRUE; - } - else if (!xdg_surface->has_set_geometry) - { - /* If the surface has never set any geometry, calculate - * a default one unioning the surface and all subsurfaces together. */ - meta_wayland_surface_calculate_window_geometry (surface, &geom, 0, 0); - } - else + if (!pending->has_new_geometry) { - /* Otherwise, keep the geometry the same. */ - - /* XXX: We don't store the geometry in any consistent place - * right now, so we can't re-fetch it. We should change - * meta_window_wayland_move_resize. */ - - /* XXX: This is the common case. Recognize it to prevent - * a warning. */ - if (pending->dx == 0 && pending->dy == 0) - return; - - g_warning ("XXX: Attach-initiated move without a new geometry. This is unimplemented right now."); + if (pending->dx != 0 || pending->dx != 0) + { + g_warning ("XXX: Attach-initiated move without a new geometry. This is unimplemented right now."); + } return; } + window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface); meta_window_wayland_move_resize (window, - &xdg_surface->acked_configure_serial, - geom, pending->dx, pending->dy); - xdg_surface->acked_configure_serial.set = FALSE; + &xdg_surface_priv->acked_configure_serial, + window_geometry, + pending->dx, pending->dy); + xdg_surface_priv->acked_configure_serial.set = FALSE; } static MetaWaylandSurface * -xdg_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role) +xdg_toplevel_role_get_toplevel (MetaWaylandSurfaceRole *surface_role) { return meta_wayland_surface_role_get_surface (surface_role); } static void -xdg_surface_role_configure (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, - int new_x, - int new_y, - int new_width, - int new_height, - MetaWaylandSerial *sent_serial) +xdg_toplevel_role_configure (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + int new_x, + int new_y, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial) { - MetaWaylandXdgSurface *xdg_surface = - META_WAYLAND_XDG_SURFACE (shell_surface_role); - MetaWaylandSurfaceRole *surface_role = - META_WAYLAND_SURFACE_ROLE (shell_surface_role); - MetaWaylandSurface *surface = - meta_wayland_surface_role_get_surface (surface_role); - struct wl_client *client = wl_resource_get_client (xdg_surface->resource); - struct wl_display *display = wl_client_get_display (client); - uint32_t serial = wl_display_next_serial (display); - struct wl_array states; + MetaWaylandXdgToplevel *xdg_toplevel = + META_WAYLAND_XDG_TOPLEVEL (shell_surface_role); + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_toplevel); + MetaWaylandXdgSurfacePrivate *xdg_surface_priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); - if (!xdg_surface->resource) + if (!xdg_surface_priv->resource) return; - wl_array_init (&states); - fill_states (&states, surface->window); - - xdg_surface_send_configure (xdg_surface->resource, - new_width, new_height, - &states, - serial); - - wl_array_release (&states); + if (!xdg_toplevel->resource) + return; - if (sent_serial) - { - sent_serial->set = TRUE; - sent_serial->value = serial; - } + meta_wayland_xdg_toplevel_send_configure (xdg_toplevel, + new_width, new_height, + sent_serial); } static void -xdg_surface_role_managed (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, - MetaWindow *window) +xdg_toplevel_role_managed (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + MetaWindow *window) { } static void -xdg_surface_role_ping (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, - uint32_t serial) +xdg_toplevel_role_close (MetaWaylandSurfaceRoleShellSurface *shell_surface_role) { - MetaWaylandXdgSurface *xdg_surface = - META_WAYLAND_XDG_SURFACE (shell_surface_role); + MetaWaylandXdgToplevel *xdg_toplevel = + META_WAYLAND_XDG_TOPLEVEL (shell_surface_role); - xdg_shell_send_ping (xdg_surface->xdg_shell_resource, serial); + zxdg_toplevel_v6_send_close (xdg_toplevel->resource); } static void -xdg_surface_role_close (MetaWaylandSurfaceRoleShellSurface *shell_surface_role) +xdg_toplevel_role_shell_client_destroyed (MetaWaylandXdgSurface *xdg_surface) { - MetaWaylandXdgSurface *xdg_surface = - META_WAYLAND_XDG_SURFACE (shell_surface_role); + MetaWaylandXdgToplevel *xdg_toplevel = + META_WAYLAND_XDG_TOPLEVEL (xdg_surface); + struct wl_resource *xdg_shell_resource = + meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + MetaWaylandXdgSurfaceClass *xdg_surface_class = + META_WAYLAND_XDG_SURFACE_CLASS (meta_wayland_xdg_toplevel_parent_class); - xdg_surface_send_close (xdg_surface->resource); + 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 -xdg_surface_role_finalize (GObject *object) +xdg_toplevel_role_finalize (GObject *object) { - MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (object); + MetaWaylandXdgToplevel *xdg_toplevel = META_WAYLAND_XDG_TOPLEVEL (object); - g_clear_pointer (&xdg_surface->resource, wl_resource_destroy); + g_clear_pointer (&xdg_toplevel->resource, wl_resource_destroy); - G_OBJECT_CLASS (meta_wayland_xdg_surface_parent_class)->finalize (object); + G_OBJECT_CLASS (meta_wayland_xdg_toplevel_parent_class)->finalize (object); } static void -meta_wayland_xdg_surface_init (MetaWaylandXdgSurface *role) +meta_wayland_xdg_toplevel_init (MetaWaylandXdgToplevel *role) { } static void -meta_wayland_xdg_surface_class_init (MetaWaylandXdgSurfaceClass *klass) +meta_wayland_xdg_toplevel_class_init (MetaWaylandXdgToplevelClass *klass) { GObjectClass *object_class; MetaWaylandSurfaceRoleClass *surface_role_class; MetaWaylandSurfaceRoleShellSurfaceClass *shell_surface_role_class; + MetaWaylandXdgSurfaceClass *xdg_surface_class; object_class = G_OBJECT_CLASS (klass); - object_class->finalize = xdg_surface_role_finalize; + object_class->finalize = xdg_toplevel_role_finalize; surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass); - surface_role_class->commit = xdg_surface_role_commit; - surface_role_class->get_toplevel = xdg_surface_role_get_toplevel; + surface_role_class->commit = xdg_toplevel_role_commit; + surface_role_class->get_toplevel = xdg_toplevel_role_get_toplevel; shell_surface_role_class = META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE_CLASS (klass); - shell_surface_role_class->configure = xdg_surface_role_configure; - shell_surface_role_class->managed = xdg_surface_role_managed; - shell_surface_role_class->ping = xdg_surface_role_ping; - shell_surface_role_class->close = xdg_surface_role_close; + shell_surface_role_class->configure = xdg_toplevel_role_configure; + shell_surface_role_class->managed = xdg_toplevel_role_managed; + shell_surface_role_class->close = xdg_toplevel_role_close; + + xdg_surface_class = META_WAYLAND_XDG_SURFACE_CLASS (klass); + xdg_surface_class->shell_client_destroyed = + xdg_toplevel_role_shell_client_destroyed; +} + +static void +finish_popup_setup (MetaWaylandXdgPopup *xdg_popup) +{ + MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (xdg_popup); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + MetaWaylandSurface *parent_surface; + MetaPlacementRule placement_rule; + MetaWaylandSeat *seat; + uint32_t serial; + MetaDisplay *display = meta_get_display (); + MetaWindow *window; + + parent_surface = xdg_popup->setup.parent_surface; + placement_rule = xdg_popup->setup.placement_rule; + 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 (seat) + { + if (!meta_wayland_seat_can_popup (seat, serial)) + { + zxdg_popup_v6_send_popup_done (xdg_popup->resource); + 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_window_place_with_placement_rule (window, &placement_rule); + meta_wayland_surface_set_window (surface, window); + + 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; + } } static void xdg_popup_role_commit (MetaWaylandSurfaceRole *surface_role, MetaWaylandPendingState *pending) { + MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (surface_role); + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role); MetaWaylandSurfaceRoleClass *surface_role_class; MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); - MetaWindow *window = surface->window; - MetaRectangle geom = { 0 }; + MetaRectangle window_geometry; + + if (xdg_popup->setup.parent_surface) + finish_popup_setup (xdg_popup); + + /* If the window disappeared the surface is not coming back. */ + if (!surface->window) + return; surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_popup_parent_class); surface_role_class->commit (surface_role, pending); - if (surface->buffer_ref.buffer == NULL) - { - /* 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_popup"); - return; - } - if (!pending->newly_attached) return; - /* If the window disappeared the surface is not coming back. */ - if (!window) + if (!surface->buffer_ref.buffer) return; - meta_wayland_surface_calculate_window_geometry (surface, &geom, 0, 0); - meta_window_wayland_move_resize (window, + window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface); + meta_window_wayland_move_resize (surface->window, NULL, - geom, pending->dx, pending->dy); + window_geometry, + pending->dx, pending->dy); } static MetaWaylandSurface * @@ -626,8 +788,27 @@ xdg_popup_role_configure (MetaWaylandSurfaceRoleShellSurface *shell_surface_role int new_height, MetaWaylandSerial *sent_serial) { - /* This can happen if the popup window loses or receives focus. - * Just ignore it. */ + MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (shell_surface_role); + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_popup); + MetaWindow *parent_window = xdg_popup->parent_surface->window; + 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; + + x = new_x - parent_window->rect.x; + y = new_y - parent_window->rect.y; + zxdg_popup_v6_send_configure (xdg_popup->resource, + x, y, new_width, new_height); + meta_wayland_xdg_surface_send_configure (xdg_surface); } static void @@ -644,12 +825,25 @@ xdg_popup_role_managed (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, } static void -xdg_popup_role_ping (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, - uint32_t serial) +xdg_popup_role_shell_client_destroyed (MetaWaylandXdgSurface *xdg_surface) { - MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (shell_surface_role); + MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (xdg_surface); + struct wl_resource *xdg_shell_resource = + meta_wayland_xdg_surface_get_shell_resource (xdg_surface); + MetaWaylandXdgSurfaceClass *xdg_surface_class = + META_WAYLAND_XDG_SURFACE_CLASS (meta_wayland_xdg_popup_parent_class); - xdg_shell_send_ping (xdg_popup->xdg_shell_resource, serial); + 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 @@ -657,13 +851,16 @@ meta_wayland_xdg_popup_done (MetaWaylandPopupSurface *popup_surface) { MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (popup_surface); - xdg_popup_send_popup_done (xdg_popup->resource); + zxdg_popup_v6_send_popup_done (xdg_popup->resource); } static void 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); MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (xdg_popup); MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); @@ -672,8 +869,8 @@ 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_popup->xdg_shell_resource, - XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, + wl_resource_post_error (xdg_shell_resource, + ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, "destroyed popup not top most popup"); } @@ -720,6 +917,7 @@ meta_wayland_xdg_popup_class_init (MetaWaylandXdgPopupClass *klass) GObjectClass *object_class; MetaWaylandSurfaceRoleClass *surface_role_class; MetaWaylandSurfaceRoleShellSurfaceClass *shell_surface_role_class; + MetaWaylandXdgSurfaceClass *xdg_surface_class; object_class = G_OBJECT_CLASS (klass); object_class->finalize = xdg_popup_role_finalize; @@ -732,169 +930,795 @@ meta_wayland_xdg_popup_class_init (MetaWaylandXdgPopupClass *klass) META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE_CLASS (klass); shell_surface_role_class->configure = xdg_popup_role_configure; shell_surface_role_class->managed = xdg_popup_role_managed; - shell_surface_role_class->ping = xdg_popup_role_ping; + + xdg_surface_class = META_WAYLAND_XDG_SURFACE_CLASS (klass); + xdg_surface_class->shell_client_destroyed = + xdg_popup_role_shell_client_destroyed; +} + +static struct wl_resource * +meta_wayland_xdg_surface_get_shell_resource (MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); + + return priv->shell_client->resource; +} + +static MetaRectangle +meta_wayland_xdg_surface_get_window_geometry (MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); + + return priv->geometry; +} + +static gboolean +meta_wayland_xdg_surface_is_assigned (MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); + + return priv->resource != NULL; +} + +static uint32_t +meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_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 -xdg_shell_get_xdg_surface (struct wl_client *client, +xdg_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource); + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_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 +xdg_surface_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +xdg_surface_get_toplevel (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + 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); + + 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 +xdg_surface_get_popup (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *parent_resource, + struct wl_resource *positioner_resource) +{ + MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource); + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_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 +xdg_surface_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 +xdg_surface_ack_configure (struct wl_client *client, struct wl_resource *resource, - guint32 id, - struct wl_resource *surface_resource) + uint32_t serial) { - MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); - MetaWaylandXdgSurface *xdg_surface; - MetaWindow *window; + MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource); + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); - if (META_IS_WAYLAND_XDG_SURFACE (surface->role) && - META_WAYLAND_XDG_SURFACE (surface->role)->resource) + priv->acked_configure_serial.set = TRUE; + priv->acked_configure_serial.value = serial; +} + +static const struct zxdg_surface_v6_interface meta_wayland_xdg_surface_interface = { + xdg_surface_destroy, + xdg_surface_get_toplevel, + xdg_surface_get_popup, + xdg_surface_set_window_geometry, + xdg_surface_ack_configure, +}; + +static void +xdg_surface_role_finalize (GObject *object) +{ + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (object); + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); + + g_clear_pointer (&priv->resource, wl_resource_destroy); + + G_OBJECT_CLASS (meta_wayland_xdg_surface_parent_class)->finalize (object); +} + +static void +xdg_surface_role_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandPendingState *pending) +{ + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role); + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_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_xdg_surface_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) { - wl_resource_post_error (surface_resource, + /* XDG surfaces can't commit NULL buffers */ + wl_resource_post_error (surface->resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "xdg_shell::get_xdg_surface already requested"); + "Cannot commit a NULL buffer to an xdg_surface"); return; } - if (!meta_wayland_surface_assign_role (surface, META_TYPE_WAYLAND_XDG_SURFACE, - NULL)) + if (surface->buffer_ref.buffer && !priv->configure_sent) { - wl_resource_post_error (resource, XDG_SHELL_ERROR_ROLE, - "wl_surface@%d already has a different role", + 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) + { + /* If the surface has never set any geometry, calculate + * a default one unioning the surface and all subsurfaces together. */ + meta_wayland_surface_calculate_window_geometry (surface, + &priv->geometry, + 0, 0); + } +} + +static void +xdg_surface_role_assigned (MetaWaylandSurfaceRole *surface_role) +{ + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role); + MetaWaylandXdgSurfacePrivate *priv = + 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); + 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; } - xdg_surface = META_WAYLAND_XDG_SURFACE (surface->role); - xdg_surface->resource = wl_resource_create (client, - &xdg_surface_interface, - wl_resource_get_version (resource), - id); - wl_resource_set_implementation (xdg_surface->resource, + surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_surface_parent_class); + surface_role_class->assigned (surface_role); +} + +static void +xdg_surface_role_ping (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + uint32_t serial) +{ + MetaWaylandXdgSurface *xdg_surface = + META_WAYLAND_XDG_SURFACE (shell_surface_role); + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); + + zxdg_shell_v6_send_ping (priv->shell_client->resource, serial); +} + +static void +xdg_surface_role_shell_client_destroyed (MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_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_xdg_surface_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (object); + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); + + switch (prop_id) + { + case XDG_SURFACE_PROP_SHELL_CLIENT: + priv->shell_client = g_value_get_pointer (value); + break; + + case XDG_SURFACE_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_xdg_surface_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (object); + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); + + switch (prop_id) + { + case XDG_SURFACE_PROP_SHELL_CLIENT: + g_value_set_pointer (value, priv->shell_client); + break; + + case XDG_SURFACE_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_xdg_surface_init (MetaWaylandXdgSurface *xdg_surface) +{ +} + +static void +meta_wayland_xdg_surface_class_init (MetaWaylandXdgSurfaceClass *klass) +{ + GObjectClass *object_class; + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurfaceRoleShellSurfaceClass *shell_surface_role_class; + GParamSpec *pspec; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = xdg_surface_role_finalize; + object_class->set_property = meta_wayland_xdg_surface_set_property; + object_class->get_property = meta_wayland_xdg_surface_get_property; + + surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass); + surface_role_class->commit = xdg_surface_role_commit; + surface_role_class->assigned = xdg_surface_role_assigned; + + shell_surface_role_class = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE_CLASS (klass); + shell_surface_role_class->ping = xdg_surface_role_ping; + + klass->shell_client_destroyed = xdg_surface_role_shell_client_destroyed; + + pspec = g_param_spec_pointer ("shell-client", + "MetaWaylandXdgShellClient", + "The shell client instance", + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, + XDG_SURFACE_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, + XDG_SURFACE_PROP_RESOURCE, + pspec); +} + +static void +meta_wayland_xdg_surface_shell_client_destroyed (MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandXdgSurfaceClass *xdg_surface_class = + META_WAYLAND_XDG_SURFACE_GET_CLASS (xdg_surface); + + xdg_surface_class->shell_client_destroyed (xdg_surface); +} + +static void +meta_wayland_xdg_surface_constructor_finalize (MetaWaylandXdgSurfaceConstructor *constructor, + MetaWaylandXdgSurface *xdg_surface) +{ + MetaWaylandXdgShellClient *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_xdg_surface_interface, xdg_surface, xdg_surface_destructor); - xdg_surface->xdg_shell_resource = resource; + g_free (constructor); +} - window = meta_window_wayland_new (meta_get_display (), surface); - meta_wayland_surface_set_window (surface, window); +static void +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 destroyed before constructed"); + wl_resource_destroy (resource); } static void -xdg_shell_get_xdg_popup (struct wl_client *client, - struct wl_resource *resource, - uint32_t id, - struct wl_resource *surface_resource, - struct wl_resource *parent_resource, - struct wl_resource *seat_resource, - uint32_t serial, - int32_t x, - int32_t y) +xdg_surface_constructor_get_toplevel (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) { - MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); - MetaWaylandPopupSurface *popup_surface; - MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); - MetaWaylandSurface *top_popup; - MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandXdgSurfaceConstructor *constructor = + wl_resource_get_user_data (resource); + MetaWaylandXdgShellClient *shell_client = constructor->shell_client; + struct wl_resource *xdg_surface_resource = constructor->resource; + MetaWaylandSurface *surface = constructor->surface; + MetaWaylandXdgToplevel *xdg_toplevel; + MetaWaylandXdgSurface *xdg_surface; MetaWindow *window; - MetaDisplay *display = meta_get_display (); - MetaWaylandXdgPopup *xdg_popup; - MetaWaylandPopup *popup; - if (META_IS_WAYLAND_XDG_POPUP (surface->role) && - META_WAYLAND_XDG_POPUP (surface->role)->resource) + if (!meta_wayland_surface_assign_role (surface, + META_TYPE_WAYLAND_XDG_TOPLEVEL, + "shell-client", shell_client, + "xdg-surface-resource", xdg_surface_resource, + NULL)) { - wl_resource_post_error (surface_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "xdg_shell::get_xdg_popup already requested"); + 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 (!meta_wayland_surface_assign_role (surface, META_TYPE_WAYLAND_XDG_POPUP, + xdg_toplevel = META_WAYLAND_XDG_TOPLEVEL (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_xdg_toplevel_interface, + xdg_toplevel, + xdg_toplevel_destructor); + + xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_toplevel); + meta_wayland_xdg_surface_constructor_finalize (constructor, xdg_surface); + + window = meta_window_wayland_new (meta_get_display (), surface); + meta_wayland_surface_set_window (surface, window); +} + +static void +xdg_surface_constructor_get_popup (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *parent_resource, + struct wl_resource *positioner_resource) +{ + MetaWaylandXdgSurfaceConstructor *constructor = + 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_surface_resource = constructor->resource; + MetaWaylandSurface *parent_surface = + surface_from_xdg_surface_resource (parent_resource); + MetaWaylandXdgPositioner *xdg_positioner; + MetaWaylandXdgPopup *xdg_popup; + MetaWaylandXdgSurface *xdg_surface; + + if (!meta_wayland_surface_assign_role (surface, + META_TYPE_WAYLAND_XDG_POPUP, + "shell-client", shell_client, + "xdg-surface-resource", xdg_surface_resource, NULL)) { - wl_resource_post_error (resource, XDG_SHELL_ERROR_ROLE, + 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 (parent_surf == NULL || - parent_surf->window == NULL || - (!META_IS_WAYLAND_XDG_POPUP (parent_surf->role) && - !META_IS_WAYLAND_XDG_SURFACE (parent_surf->role))) + xdg_popup = META_WAYLAND_XDG_POPUP (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_xdg_popup_interface, + xdg_popup, + xdg_popup_destructor); + + xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_popup); + meta_wayland_xdg_surface_constructor_finalize (constructor, xdg_surface); + + xdg_positioner = wl_resource_get_user_data (positioner_resource); + xdg_popup->setup.placement_rule = + meta_wayland_xdg_positioner_to_placement (xdg_positioner); + xdg_popup->setup.parent_surface = parent_surface; +} + +static void +xdg_surface_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 +xdg_surface_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_xdg_surface_constructor_interface = { + xdg_surface_constructor_destroy, + xdg_surface_constructor_get_toplevel, + xdg_surface_constructor_get_popup, + xdg_surface_constructor_set_window_geometry, + xdg_surface_constructor_ack_configure, +}; + +static void +xdg_surface_constructor_destructor (struct wl_resource *resource) +{ + MetaWaylandXdgSurfaceConstructor *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_xdg_positioner_to_placement (MetaWaylandXdgPositioner *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 +meta_wayland_xdg_positioner_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +meta_wayland_xdg_positioner_set_size (struct wl_client *client, + struct wl_resource *resource, + int32_t width, + int32_t height) +{ + MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource); + + if (width <= 0 || height <= 0) { - wl_resource_post_error (resource, - XDG_SHELL_ERROR_INVALID_POPUP_PARENT, - "invalid parent surface"); + wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + "Invalid size"); return; } - top_popup = meta_wayland_pointer_get_top_popup (&seat->pointer); - if ((top_popup == NULL && !META_IS_WAYLAND_XDG_SURFACE (parent_surf->role)) || - (top_popup != NULL && parent_surf != top_popup)) + positioner->width = width; + positioner->height = height; +} + +static void +meta_wayland_xdg_positioner_set_anchor_rect (struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource); + + if (width <= 0 || height <= 0) { - wl_resource_post_error (resource, - XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, - "parent not top most surface"); + wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + "Invalid anchor rectangle size"); return; } - xdg_popup = META_WAYLAND_XDG_POPUP (surface->role); - xdg_popup->resource = wl_resource_create (client, &xdg_popup_interface, - wl_resource_get_version (resource), id); - wl_resource_set_implementation (xdg_popup->resource, - &meta_wayland_xdg_popup_interface, - xdg_popup, - xdg_popup_destructor); + positioner->anchor_rect = (MetaRectangle) { + .x = x, + .y = y, + .width = width, + .height = height, + }; +} - xdg_popup->xdg_shell_resource = resource; +static void +meta_wayland_xdg_positioner_set_anchor (struct wl_client *client, + struct wl_resource *resource, + uint32_t anchor) +{ + MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource); - if (!meta_wayland_seat_can_popup (seat, serial)) + 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)) { - xdg_popup_send_popup_done (xdg_popup->resource); + wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + "Invalid anchor"); return; } - xdg_popup->parent_surface = parent_surf; - xdg_popup->parent_destroy_listener.notify = handle_popup_parent_destroyed; - wl_resource_add_destroy_listener (parent_surf->resource, - &xdg_popup->parent_destroy_listener); + positioner->anchor = anchor; +} - window = meta_window_wayland_new (display, surface); - meta_window_wayland_place_relative_to (window, parent_surf->window, x, y); - window->showing_for_first_time = FALSE; +static void +meta_wayland_xdg_positioner_set_gravity (struct wl_client *client, + struct wl_resource *resource, + uint32_t gravity) +{ + MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource); - meta_wayland_surface_set_window (surface, window); + 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; +} - 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) +static void +meta_wayland_xdg_positioner_set_constraint_adjustment (struct wl_client *client, + struct wl_resource *resource, + 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); + + + if ((constraint_adjustment & ~all_adjustments) != 0) { - xdg_popup_send_popup_done (xdg_popup->resource); - meta_wayland_surface_destroy_window (surface); + wl_resource_post_error (resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, + "Invalid constraint action"); return; } - xdg_popup->popup = popup; + positioner->constraint_adjustment = constraint_adjustment; +} + +static void +meta_wayland_xdg_positioner_set_offset (struct wl_client *client, + struct wl_resource *resource, + int32_t x, + int32_t y) +{ + MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource); + + positioner->offset_x = x; + positioner->offset_y = y; +} + +static const struct zxdg_positioner_v6_interface meta_wayland_xdg_positioner_interface = { + meta_wayland_xdg_positioner_destroy, + meta_wayland_xdg_positioner_set_size, + meta_wayland_xdg_positioner_set_anchor_rect, + meta_wayland_xdg_positioner_set_anchor, + meta_wayland_xdg_positioner_set_gravity, + meta_wayland_xdg_positioner_set_constraint_adjustment, + meta_wayland_xdg_positioner_set_offset, +}; + +static void +xdg_positioner_destructor (struct wl_resource *resource) +{ + MetaWaylandXdgPositioner *positioner = wl_resource_get_user_data (resource); + + g_free (positioner); } static void xdg_shell_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_destroy (resource); } static void -xdg_shell_use_unstable_version (struct wl_client *client, - struct wl_resource *resource, - int32_t version) +xdg_shell_create_positioner (struct wl_client *client, + struct wl_resource *resource, + uint32_t id) { - if (version != XDG_SHELL_VERSION_CURRENT) - wl_resource_post_error (resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "bad xdg-shell version: %d\n", version); + MetaWaylandXdgPositioner *positioner; + struct wl_resource *positioner_resource; + + positioner = g_new0 (MetaWaylandXdgPositioner, 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_xdg_positioner_interface, + positioner, + xdg_positioner_destructor); +} + +static void +xdg_shell_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); + MetaWaylandXdgSurfaceConstructor *constructor; + + if (surface->role && !META_IS_WAYLAND_XDG_SURFACE (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 && META_IS_WAYLAND_XDG_SURFACE (surface->role) && + 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"); + 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 (MetaWaylandXdgSurfaceConstructor, 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_xdg_surface_constructor_interface, + constructor, + xdg_surface_constructor_destructor); + + shell_client->surface_constructors = + g_list_append (shell_client->surface_constructors, constructor); } static void @@ -907,39 +1731,62 @@ xdg_shell_pong (struct wl_client *client, meta_display_pong_for_serial (display, serial); } -static const struct xdg_shell_interface meta_wayland_xdg_shell_interface = { +static const struct zxdg_shell_v6_interface meta_wayland_xdg_shell_interface = { xdg_shell_destroy, - xdg_shell_use_unstable_version, + xdg_shell_create_positioner, xdg_shell_get_xdg_surface, - xdg_shell_get_xdg_popup, xdg_shell_pong, }; static void +xdg_shell_destructor (struct wl_resource *resource) +{ + MetaWaylandXdgShellClient *shell_client = wl_resource_get_user_data (resource); + + while (shell_client->surface_constructors) + { + MetaWaylandXdgSurfaceConstructor *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) + { + MetaWaylandXdgSurface *xdg_surface = + g_list_first (shell_client->surfaces)->data; + + meta_wayland_xdg_surface_shell_client_destroyed (xdg_surface); + } + g_list_free (shell_client->surfaces); + + g_free (shell_client); +} + +static void bind_xdg_shell (struct wl_client *client, void *data, guint32 version, guint32 id) { - struct wl_resource *resource; + MetaWaylandXdgShellClient *shell_client; - if (version != META_XDG_SHELL_VERSION) - { - g_warning ("using xdg-shell without stable version %d\n", - META_XDG_SHELL_VERSION); - return; - } + shell_client = g_new0 (MetaWaylandXdgShellClient, 1); - resource = wl_resource_create (client, &xdg_shell_interface, version, id); - wl_resource_set_implementation (resource, &meta_wayland_xdg_shell_interface, - data, NULL); + shell_client->resource = wl_resource_create (client, + &zxdg_shell_v6_interface, + version, id); + wl_resource_set_implementation (shell_client->resource, + &meta_wayland_xdg_shell_interface, + shell_client, xdg_shell_destructor); } void meta_wayland_xdg_shell_init (MetaWaylandCompositor *compositor) { if (wl_global_create (compositor->wayland_display, - &xdg_shell_interface, + &zxdg_shell_v6_interface, META_XDG_SHELL_VERSION, compositor, bind_xdg_shell) == 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 d0b1953de..8249f0f53 100644 --- a/src/wayland/meta-wayland-xdg-shell.h +++ b/src/wayland/meta-wayland-xdg-shell.h @@ -23,16 +23,29 @@ #include "wayland/meta-wayland-surface.h" #define META_TYPE_WAYLAND_XDG_SURFACE (meta_wayland_xdg_surface_get_type ()) -G_DECLARE_FINAL_TYPE (MetaWaylandXdgSurface, - meta_wayland_xdg_surface, - META, WAYLAND_XDG_SURFACE, - MetaWaylandSurfaceRoleShellSurface); +G_DECLARE_DERIVABLE_TYPE (MetaWaylandXdgSurface, + meta_wayland_xdg_surface, + META, WAYLAND_XDG_SURFACE, + MetaWaylandSurfaceRoleShellSurface); + +struct _MetaWaylandXdgSurfaceClass +{ + MetaWaylandSurfaceRoleShellSurfaceClass parent_class; + + void (*shell_client_destroyed) (MetaWaylandXdgSurface *xdg_surface); +}; + +#define META_TYPE_WAYLAND_XDG_TOPLEVEL (meta_wayland_xdg_toplevel_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandXdgToplevel, + meta_wayland_xdg_toplevel, + META, WAYLAND_XDG_TOPLEVEL, + MetaWaylandXdgSurface); #define META_TYPE_WAYLAND_XDG_POPUP (meta_wayland_xdg_popup_get_type ()) G_DECLARE_FINAL_TYPE (MetaWaylandXdgPopup, meta_wayland_xdg_popup, META, WAYLAND_XDG_POPUP, - MetaWaylandSurfaceRoleShellSurface); + MetaWaylandXdgSurface); void meta_wayland_xdg_shell_init (MetaWaylandCompositor *compositor); |