diff --git a/src/Makefile.am b/src/Makefile.am index 8f6a781f1..f3b15f34f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -302,6 +302,10 @@ libmutter_la_SOURCES += \ wayland/meta-wayland-outputs.h \ wayland/meta-window-wayland.c \ wayland/meta-window-wayland.h \ + wayland/meta-wayland-xdg-shell.c \ + wayland/meta-wayland-xdg-shell.h \ + wayland/meta-wayland-wl-shell.c \ + wayland/meta-wayland-wl-shell.h \ $(NULL) endif diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 4699cfd57..b984671b8 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -31,7 +31,6 @@ #include #include "gtk-shell-server-protocol.h" -#include "xdg-shell-unstable-v5-server-protocol.h" #include "meta-wayland-private.h" #include "meta-xwayland-private.h" @@ -40,9 +39,10 @@ #include "meta-wayland-seat.h" #include "meta-wayland-keyboard.h" #include "meta-wayland-pointer.h" -#include "meta-wayland-popup.h" #include "meta-wayland-data-device.h" #include "meta-wayland-outputs.h" +#include "meta-wayland-xdg-shell.h" +#include "meta-wayland-wl-shell.h" #include "meta-cursor-tracker-private.h" #include "display-private.h" @@ -88,6 +88,14 @@ G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRole, meta_wayland_surface_role, G_TYPE_OBJECT); +G_DEFINE_TYPE (MetaWaylandSurfaceRoleActorSurface, + meta_wayland_surface_role_actor_surface, + META_TYPE_WAYLAND_SURFACE_ROLE); + +G_DEFINE_TYPE (MetaWaylandSurfaceRoleShellSurface, + meta_wayland_surface_role_shell_surface, + META_TYPE_WAYLAND_SURFACE_ROLE_ACTOR_SURFACE); + G_DEFINE_TYPE (MetaWaylandPendingState, meta_wayland_pending_state, G_TYPE_OBJECT); @@ -99,34 +107,7 @@ struct _MetaWaylandSurfaceRoleSubsurface G_DEFINE_TYPE (MetaWaylandSurfaceRoleSubsurface, meta_wayland_surface_role_subsurface, - META_TYPE_WAYLAND_SURFACE_ROLE); - -struct _MetaWaylandSurfaceRoleXdgSurface -{ - MetaWaylandSurfaceRole parent; -}; - -G_DEFINE_TYPE (MetaWaylandSurfaceRoleXdgSurface, - meta_wayland_surface_role_xdg_surface, - META_TYPE_WAYLAND_SURFACE_ROLE); - -struct _MetaWaylandSurfaceRoleXdgPopup -{ - MetaWaylandSurfaceRole parent; -}; - -G_DEFINE_TYPE (MetaWaylandSurfaceRoleXdgPopup, - meta_wayland_surface_role_xdg_popup, - META_TYPE_WAYLAND_SURFACE_ROLE); - -struct _MetaWaylandSurfaceRoleWlShellSurface -{ - MetaWaylandSurfaceRole parent; -}; - -G_DEFINE_TYPE (MetaWaylandSurfaceRoleWlShellSurface, - meta_wayland_surface_role_wl_shell_surface, - META_TYPE_WAYLAND_SURFACE_ROLE); + META_TYPE_WAYLAND_SURFACE_ROLE_ACTOR_SURFACE); struct _MetaWaylandSurfaceRoleDND { @@ -152,6 +133,22 @@ static gboolean meta_wayland_surface_role_is_on_output (MetaWaylandSurfaceRole *surface_role, MetaMonitorInfo *info); +static void +meta_wayland_surface_role_shell_surface_configure (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial); + +static void +meta_wayland_surface_role_shell_surface_ping (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + uint32_t serial); + +static void +meta_wayland_surface_role_shell_surface_close (MetaWaylandSurfaceRoleShellSurface *shell_surface_role); + +static void +meta_wayland_surface_role_shell_surface_popup_done (MetaWaylandSurfaceRoleShellSurface *shell_surface_role); + gboolean meta_wayland_surface_assign_role (MetaWaylandSurface *surface, GType role_type) @@ -296,8 +293,8 @@ calculate_surface_window_geometry (MetaWaylandSurface *surface, } } -static void -destroy_window (MetaWaylandSurface *surface) +void +meta_wayland_surface_destroy_window (MetaWaylandSurface *surface) { if (surface->window) { @@ -352,50 +349,12 @@ queue_surface_actor_frame_callbacks (MetaWaylandSurface *surface, wl_list_init (&pending->frame_callback_list); } -static void -toplevel_surface_commit (MetaWaylandSurfaceRole *surface_role, - MetaWaylandPendingState *pending) +void +meta_wayland_surface_apply_window_state (MetaWaylandSurface *surface, + MetaWaylandPendingState *pending) { - MetaWaylandSurface *surface = - meta_wayland_surface_role_get_surface (surface_role); - MetaWaylandBuffer *buffer = surface->buffer_ref.buffer; MetaWindow *window = surface->window; - - queue_surface_actor_frame_callbacks (surface, pending); - - /* If there's no new buffer pending, then there's nothing else to - * do - */ - if (!pending->newly_attached) - return; - - if (META_IS_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE (surface->role)) - { - /* For wl_shell, it's equivalent to an unmap. Semantics - * are poorly defined, so we can choose some that are - * convenient for us. */ - if (buffer && !window) - { - window = meta_window_wayland_new (meta_get_display (), surface); - meta_wayland_surface_set_window (surface, window); - } - else if (buffer == NULL && window) - { - destroy_window (surface); - return; - } - } - else - { - if (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_surface"); - return; - } - } + MetaWaylandBuffer *buffer = surface->buffer_ref.buffer; /* Update the state of the MetaWindow if we still have one. We might not if * the window was unmanaged (for example popup destroyed, NULL buffer attached to @@ -1180,7 +1139,7 @@ wl_surface_destructor (struct wl_resource *resource) * the client is disconnecting, as the resources are destroyed in a random * order. Simply destroy the window in this case. */ if (surface->window) - destroy_window (surface); + meta_wayland_surface_destroy_window (surface); if (surface->unassigned.buffer) { @@ -1269,113 +1228,12 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor, return surface; } -static void -xdg_shell_destroy (struct wl_client *client, - struct wl_resource *resource) -{ - wl_resource_destroy (resource); -} - -static void -xdg_shell_use_unstable_version (struct wl_client *client, - struct wl_resource *resource, - int32_t version) -{ - if (version != XDG_SHELL_VERSION_CURRENT) - wl_resource_post_error (resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "bad xdg-shell version: %d\n", version); -} - -static void -xdg_shell_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 void -xdg_surface_destructor (struct wl_resource *resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, - surface); - destroy_window (surface); - surface->xdg_surface = NULL; -} - -static void -xdg_surface_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) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - MetaWindow *transient_for = NULL; - - if (parent_resource) - { - MetaWaylandSurface *parent_surface = wl_resource_get_user_data (parent_resource); - transient_for = parent_surface->window; - } - - meta_window_set_transient_for (surface->window, transient_for); -} - -static void -xdg_surface_set_title (struct wl_client *client, - struct wl_resource *resource, - const char *title) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - meta_window_set_title (surface->window, title); -} - -static void -xdg_surface_set_app_id (struct wl_client *client, - struct wl_resource *resource, - const char *app_id) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - meta_window_set_wm_class (surface->window, app_id, app_id); -} - -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) -{ - MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - if (!meta_wayland_seat_get_grab_info (seat, surface, serial, FALSE, NULL, NULL)) - return; - - meta_window_show_menu (surface->window, META_WINDOW_MENU_WM, - surface->window->buffer_rect.x + x, - surface->window->buffer_rect.y + y); -} - -static gboolean -begin_grab_op_on_surface (MetaWaylandSurface *surface, - MetaWaylandSeat *seat, - MetaGrabOp grab_op, - gfloat x, - gfloat y) +gboolean +meta_wayland_surface_begin_grab_op (MetaWaylandSurface *surface, + MetaWaylandSeat *seat, + MetaGrabOp grab_op, + gfloat x, + gfloat y) { MetaWindow *window = surface->window; @@ -1397,648 +1255,6 @@ begin_grab_op_on_surface (MetaWaylandSurface *surface, x, y); } -static void -xdg_surface_move (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *seat_resource, - guint32 serial) -{ - MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - gfloat x, y; - - if (!meta_wayland_seat_get_grab_info (seat, surface, serial, TRUE, &x, &y)) - return; - - begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING, x, y); -} - -static MetaGrabOp -grab_op_for_xdg_surface_resize_edge (int edge) -{ - MetaGrabOp op = META_GRAB_OP_WINDOW_BASE; - - if (edge & XDG_SURFACE_RESIZE_EDGE_TOP) - op |= META_GRAB_OP_WINDOW_DIR_NORTH; - if (edge & XDG_SURFACE_RESIZE_EDGE_BOTTOM) - op |= META_GRAB_OP_WINDOW_DIR_SOUTH; - if (edge & XDG_SURFACE_RESIZE_EDGE_LEFT) - op |= META_GRAB_OP_WINDOW_DIR_WEST; - if (edge & XDG_SURFACE_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 -xdg_surface_resize (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *seat_resource, - guint32 serial, - guint32 edges) -{ - MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - gfloat x, y; - - if (!meta_wayland_seat_get_grab_info (seat, surface, serial, TRUE, &x, &y)) - return; - - begin_grab_op_on_surface (surface, seat, grab_op_for_xdg_surface_resize_edge (edges), x, y); -} - -static void -xdg_surface_ack_configure (struct wl_client *client, - struct wl_resource *resource, - uint32_t serial) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - surface->acked_configure_serial.set = TRUE; - surface->acked_configure_serial.value = serial; -} - -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 = wl_resource_get_user_data (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_set_maximized (struct wl_client *client, - struct wl_resource *resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); -} - -static void -xdg_surface_unset_maximized (struct wl_client *client, - struct wl_resource *resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (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) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - meta_window_make_fullscreen (surface->window); -} - -static void -xdg_surface_unset_fullscreen (struct wl_client *client, - struct wl_resource *resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - meta_window_unmake_fullscreen (surface->window); -} - -static void -xdg_surface_set_minimized (struct wl_client *client, - struct wl_resource *resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (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 void -xdg_shell_get_xdg_surface (struct wl_client *client, - struct wl_resource *resource, - guint32 id, - struct wl_resource *surface_resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); - MetaWindow *window; - - if (surface->xdg_surface != NULL) - { - wl_resource_post_error (surface_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "xdg_shell::get_xdg_surface already requested"); - return; - } - - if (!meta_wayland_surface_assign_role (surface, - META_TYPE_WAYLAND_SURFACE_ROLE_XDG_SURFACE)) - { - wl_resource_post_error (resource, XDG_SHELL_ERROR_ROLE, - "wl_surface@%d already has a different role", - wl_resource_get_id (surface->resource)); - return; - } - - surface->xdg_surface = wl_resource_create (client, &xdg_surface_interface, wl_resource_get_version (resource), id); - wl_resource_set_implementation (surface->xdg_surface, &meta_wayland_xdg_surface_interface, surface, xdg_surface_destructor); - - surface->xdg_shell_resource = resource; - - window = meta_window_wayland_new (meta_get_display (), surface); - meta_wayland_surface_set_window (surface, window); -} - -static void -xdg_popup_destructor (struct wl_resource *resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, - surface); - if (surface->popup.parent) - { - wl_list_remove (&surface->popup.parent_destroy_listener.link); - surface->popup.parent = NULL; - } - - if (surface->popup.popup) - meta_wayland_popup_dismiss (surface->popup.popup); - - surface->xdg_popup = NULL; -} - -static void -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 = { - xdg_popup_destroy, -}; - -static void -handle_popup_parent_destroyed (struct wl_listener *listener, void *data) -{ - MetaWaylandSurface *surface = - wl_container_of (listener, surface, popup.parent_destroy_listener); - - wl_resource_post_error (surface->xdg_shell_resource, - XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, - "destroyed popup not top most popup"); - surface->popup.parent = NULL; - - destroy_window (surface); -} - -static void -handle_popup_destroyed (struct wl_listener *listener, void *data) -{ - MetaWaylandPopup *popup = data; - MetaWaylandSurface *top_popup; - MetaWaylandSurface *surface = - wl_container_of (listener, surface, popup.destroy_listener); - - top_popup = meta_wayland_popup_get_top_popup (popup); - if (surface != top_popup) - { - wl_resource_post_error (surface->xdg_shell_resource, - XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, - "destroyed popup not top most popup"); - } - - surface->popup.popup = NULL; - - destroy_window (surface); -} - -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) -{ - struct wl_resource *popup_resource; - MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); - MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); - MetaWaylandSurface *top_popup; - MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); - MetaWindow *window; - MetaDisplay *display = meta_get_display (); - MetaWaylandPopup *popup; - - if (surface->xdg_popup != NULL) - { - wl_resource_post_error (surface_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "xdg_shell::get_xdg_popup already requested"); - return; - } - - if (!meta_wayland_surface_assign_role (surface, - META_TYPE_WAYLAND_SURFACE_ROLE_XDG_POPUP)) - { - wl_resource_post_error (resource, XDG_SHELL_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 || - (parent_surf->xdg_popup == NULL && parent_surf->xdg_surface == NULL)) - { - wl_resource_post_error (resource, - XDG_SHELL_ERROR_INVALID_POPUP_PARENT, - "invalid parent surface"); - return; - } - - top_popup = meta_wayland_pointer_get_top_popup (&seat->pointer); - if ((top_popup == NULL && parent_surf->xdg_surface == NULL) || - (top_popup != NULL && parent_surf != top_popup)) - { - wl_resource_post_error (resource, - XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, - "parent not top most surface"); - return; - } - - popup_resource = wl_resource_create (client, &xdg_popup_interface, - wl_resource_get_version (resource), id); - wl_resource_set_implementation (popup_resource, - &meta_wayland_xdg_popup_interface, - surface, - xdg_popup_destructor); - - surface->xdg_popup = popup_resource; - surface->xdg_shell_resource = resource; - - if (!meta_wayland_seat_can_popup (seat, serial)) - { - xdg_popup_send_popup_done (popup_resource); - return; - } - - surface->popup.parent = parent_surf; - surface->popup.parent_destroy_listener.notify = handle_popup_parent_destroyed; - wl_resource_add_destroy_listener (parent_surf->resource, - &surface->popup.parent_destroy_listener); - - 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; - - meta_wayland_surface_set_window (surface, window); - - meta_window_focus (window, meta_display_get_current_time (display)); - popup = meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); - if (popup == NULL) - { - destroy_window (surface); - return; - } - - surface->popup.destroy_listener.notify = handle_popup_destroyed; - surface->popup.popup = popup; - wl_signal_add (meta_wayland_popup_get_destroy_signal (popup), - &surface->popup.destroy_listener); -} - -static const struct xdg_shell_interface meta_wayland_xdg_shell_interface = { - xdg_shell_destroy, - xdg_shell_use_unstable_version, - xdg_shell_get_xdg_surface, - xdg_shell_get_xdg_popup, - xdg_shell_pong, -}; - -static void -bind_xdg_shell (struct wl_client *client, - void *data, - guint32 version, - guint32 id) -{ - struct wl_resource *resource; - - if (version != META_XDG_SHELL_VERSION) - { - g_warning ("using xdg-shell without stable version %d\n", META_XDG_SHELL_VERSION); - return; - } - - resource = wl_resource_create (client, &xdg_shell_interface, version, id); - wl_resource_set_implementation (resource, &meta_wayland_xdg_shell_interface, data, NULL); -} - -static void -wl_shell_surface_destructor (struct wl_resource *resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, - surface); - surface->wl_shell_surface = NULL; -} - -static void -wl_shell_surface_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 void -wl_shell_surface_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 = wl_resource_get_user_data (resource); - gfloat x, y; - - if (!meta_wayland_seat_get_grab_info (seat, surface, serial, TRUE, &x, &y)) - return; - - begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING, x, y); -} - -static MetaGrabOp -grab_op_for_wl_shell_surface_resize_edge (int edge) -{ - MetaGrabOp op = META_GRAB_OP_WINDOW_BASE; - - if (edge & WL_SHELL_SURFACE_RESIZE_TOP) - op |= META_GRAB_OP_WINDOW_DIR_NORTH; - if (edge & WL_SHELL_SURFACE_RESIZE_BOTTOM) - op |= META_GRAB_OP_WINDOW_DIR_SOUTH; - if (edge & WL_SHELL_SURFACE_RESIZE_LEFT) - op |= META_GRAB_OP_WINDOW_DIR_WEST; - if (edge & WL_SHELL_SURFACE_RESIZE_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 -wl_shell_surface_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 = wl_resource_get_user_data (resource); - gfloat x, y; - - if (!meta_wayland_seat_get_grab_info (seat, surface, serial, TRUE, &x, &y)) - return; - - begin_grab_op_on_surface (surface, seat, grab_op_for_wl_shell_surface_resize_edge (edges), x, y); -} - -typedef enum { - SURFACE_STATE_TOPLEVEL, - SURFACE_STATE_FULLSCREEN, - SURFACE_STATE_MAXIMIZED, -} SurfaceState; - -static void -wl_shell_surface_set_state (MetaWaylandSurface *surface, - SurfaceState state) -{ - if (state == SURFACE_STATE_FULLSCREEN) - meta_window_make_fullscreen (surface->window); - else - meta_window_unmake_fullscreen (surface->window); - - if (state == SURFACE_STATE_MAXIMIZED) - meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); - else - meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH); -} - -static void -wl_shell_surface_set_toplevel (struct wl_client *client, - struct wl_resource *resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); -} - -static void -wl_shell_surface_set_transient (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *parent_resource, - int32_t x, - int32_t y, - uint32_t flags) -{ - MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); - - meta_window_set_transient_for (surface->window, parent_surf->window); - meta_window_wayland_place_relative_to (surface->window, - parent_surf->window, - x, y); -} - -static void -wl_shell_surface_set_fullscreen (struct wl_client *client, - struct wl_resource *resource, - uint32_t method, - uint32_t framerate, - struct wl_resource *output) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - wl_shell_surface_set_state (surface, SURFACE_STATE_FULLSCREEN); -} - -static void -handle_wl_shell_popup_parent_destroyed (struct wl_listener *listener, - void *data) -{ - MetaWaylandSurface *surface = - wl_container_of (listener, surface, popup.parent_destroy_listener); - - wl_list_remove (&surface->popup.parent_destroy_listener.link); - surface->popup.parent = NULL; -} - -static void -wl_shell_surface_set_popup (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *seat_resource, - uint32_t serial, - struct wl_resource *parent_resource, - int32_t x, - int32_t y, - uint32_t flags) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); - MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); - - wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); - - if (!meta_wayland_seat_can_popup (seat, serial)) - { - wl_shell_surface_send_popup_done (resource); - return; - } - - meta_window_set_transient_for (surface->window, parent_surf->window); - meta_window_wayland_place_relative_to (surface->window, - parent_surf->window, - x, y); - - if (!surface->popup.parent) - { - surface->popup.parent = parent_surf; - surface->popup.parent_destroy_listener.notify = - handle_wl_shell_popup_parent_destroyed; - wl_resource_add_destroy_listener (parent_surf->resource, - &surface->popup.parent_destroy_listener); - } - - meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); -} - -static void -wl_shell_surface_set_maximized (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *output) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - wl_shell_surface_set_state (surface, SURFACE_STATE_MAXIMIZED); -} - -static void -wl_shell_surface_set_title (struct wl_client *client, - struct wl_resource *resource, - const char *title) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - meta_window_set_title (surface->window, title); -} - -static void -wl_shell_surface_set_class (struct wl_client *client, - struct wl_resource *resource, - const char *class_) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - meta_window_set_wm_class (surface->window, class_, class_); -} - -static const struct wl_shell_surface_interface meta_wayland_wl_shell_surface_interface = { - wl_shell_surface_pong, - wl_shell_surface_move, - wl_shell_surface_resize, - wl_shell_surface_set_toplevel, - wl_shell_surface_set_transient, - wl_shell_surface_set_fullscreen, - wl_shell_surface_set_popup, - wl_shell_surface_set_maximized, - wl_shell_surface_set_title, - wl_shell_surface_set_class, -}; - -static void -wl_shell_get_shell_surface (struct wl_client *client, - struct wl_resource *resource, - uint32_t id, - struct wl_resource *surface_resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); - MetaWindow *window; - - if (surface->wl_shell_surface != NULL) - { - wl_resource_post_error (surface_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "wl_shell::get_shell_surface already requested"); - return; - } - - if (!meta_wayland_surface_assign_role (surface, - META_TYPE_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE)) - { - wl_resource_post_error (resource, WL_SHELL_ERROR_ROLE, - "wl_surface@%d already has a different role", - wl_resource_get_id (surface->resource)); - return; - } - - surface->wl_shell_surface = wl_resource_create (client, &wl_shell_surface_interface, wl_resource_get_version (resource), id); - wl_resource_set_implementation (surface->wl_shell_surface, &meta_wayland_wl_shell_surface_interface, surface, wl_shell_surface_destructor); - - window = meta_window_wayland_new (meta_get_display (), surface); - meta_wayland_surface_set_window (surface, window); -} - -static const struct wl_shell_interface meta_wayland_wl_shell_interface = { - wl_shell_get_shell_surface, -}; - -static void -bind_wl_shell (struct wl_client *client, - void *data, - uint32_t version, - uint32_t id) -{ - struct wl_resource *resource; - - resource = wl_resource_create (client, &wl_shell_interface, version, id); - wl_resource_set_implementation (resource, &meta_wayland_wl_shell_interface, data, NULL); -} - static void gtk_surface_destructor (struct wl_resource *resource) { @@ -2452,17 +1668,8 @@ bind_subcompositor (struct wl_client *client, void meta_wayland_shell_init (MetaWaylandCompositor *compositor) { - if (wl_global_create (compositor->wayland_display, - &xdg_shell_interface, - META_XDG_SHELL_VERSION, - compositor, bind_xdg_shell) == NULL) - g_error ("Failed to register a global xdg-shell object"); - - if (wl_global_create (compositor->wayland_display, - &wl_shell_interface, - META_WL_SHELL_VERSION, - compositor, bind_wl_shell) == NULL) - g_error ("Failed to register a global wl-shell object"); + meta_wayland_xdg_shell_init (compositor); + meta_wayland_wl_shell_init (compositor); if (wl_global_create (compositor->wayland_display, >k_shell1_interface, @@ -2477,95 +1684,46 @@ meta_wayland_shell_init (MetaWaylandCompositor *compositor) g_error ("Failed to register a global wl-subcompositor object"); } -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 = XDG_SURFACE_STATE_MAXIMIZED; - } - if (meta_window_is_fullscreen (window)) - { - s = wl_array_add (states, sizeof *s); - *s = XDG_SURFACE_STATE_FULLSCREEN; - } - if (meta_grab_op_is_resizing (window->display->grab_op)) - { - s = wl_array_add (states, sizeof *s); - *s = XDG_SURFACE_STATE_RESIZING; - } - if (meta_window_appears_focused (window)) - { - s = wl_array_add (states, sizeof *s); - *s = XDG_SURFACE_STATE_ACTIVATED; - } -} - void meta_wayland_surface_configure_notify (MetaWaylandSurface *surface, int new_width, int new_height, MetaWaylandSerial *sent_serial) { - if (surface->xdg_surface) - { - struct wl_client *client = wl_resource_get_client (surface->xdg_surface); - struct wl_display *display = wl_client_get_display (client); - uint32_t serial = wl_display_next_serial (display); - struct wl_array states; + MetaWaylandSurfaceRoleShellSurface *shell_surface_role = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE (surface->role); - wl_array_init (&states); - fill_states (&states, surface->window); - - xdg_surface_send_configure (surface->xdg_surface, new_width, new_height, &states, serial); - - wl_array_release (&states); - - if (sent_serial) - { - sent_serial->set = TRUE; - sent_serial->value = serial; - } - } - else if (surface->xdg_popup) - { - /* This can happen if the popup window loses or receives focus. - * Just ignore it. */ - } - else if (surface->wl_shell_surface) - wl_shell_surface_send_configure (surface->wl_shell_surface, - 0, new_width, new_height); - else - g_assert_not_reached (); + meta_wayland_surface_role_shell_surface_configure (shell_surface_role, + new_width, new_height, + sent_serial); } void meta_wayland_surface_ping (MetaWaylandSurface *surface, guint32 serial) { - if (surface->xdg_shell_resource) - xdg_shell_send_ping (surface->xdg_shell_resource, serial); - else if (surface->wl_shell_surface) - wl_shell_surface_send_ping (surface->wl_shell_surface, serial); + MetaWaylandSurfaceRoleShellSurface *shell_surface_role = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE (surface->role); + + meta_wayland_surface_role_shell_surface_ping (shell_surface_role, serial); } void meta_wayland_surface_delete (MetaWaylandSurface *surface) { - if (surface->xdg_surface) - xdg_surface_send_close (surface->xdg_surface); + MetaWaylandSurfaceRoleShellSurface *shell_surface_role = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE (surface->role); + + meta_wayland_surface_role_shell_surface_close (shell_surface_role); } void meta_wayland_surface_popup_done (MetaWaylandSurface *surface) { - if (surface->xdg_popup) - xdg_popup_send_popup_done (surface->xdg_popup); - else if (surface->wl_shell_surface) - wl_shell_surface_send_popup_done (surface->wl_shell_surface); + MetaWaylandSurfaceRoleShellSurface *shell_surface_role = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE (surface->role); + + meta_wayland_surface_role_shell_surface_popup_done (shell_surface_role); } void @@ -2738,6 +1896,49 @@ meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role) return priv->surface; } +static void +meta_wayland_surface_role_shell_surface_configure (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial) +{ + MetaWaylandSurfaceRoleShellSurfaceClass *shell_surface_role_class = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE_GET_CLASS (shell_surface_role); + + shell_surface_role_class->configure (shell_surface_role, + new_width, + new_height, + sent_serial); +} + +static void +meta_wayland_surface_role_shell_surface_ping (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + uint32_t serial) +{ + MetaWaylandSurfaceRoleShellSurfaceClass *shell_surface_role_class = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE_GET_CLASS (shell_surface_role); + + shell_surface_role_class->ping (shell_surface_role, serial); +} + +static void +meta_wayland_surface_role_shell_surface_close (MetaWaylandSurfaceRoleShellSurface *shell_surface_role) +{ + MetaWaylandSurfaceRoleShellSurfaceClass *shell_surface_role_class = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE_GET_CLASS (shell_surface_role); + + shell_surface_role_class->close (shell_surface_role); +} + +static void +meta_wayland_surface_role_shell_surface_popup_done (MetaWaylandSurfaceRoleShellSurface *shell_surface_role) +{ + MetaWaylandSurfaceRoleShellSurfaceClass *shell_surface_role_class = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE_GET_CLASS (shell_surface_role); + + shell_surface_role_class->popup_done (shell_surface_role); +} + void meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface) { @@ -2768,6 +1969,42 @@ actor_surface_assigned (MetaWaylandSurfaceRole *surface_role) wl_list_init (&surface->pending_frame_callback_list); } +static void +actor_surface_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandPendingState *pending) +{ + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + queue_surface_actor_frame_callbacks (surface, pending); +} + +static void +meta_wayland_surface_role_actor_surface_init (MetaWaylandSurfaceRoleActorSurface *role) +{ +} + +static void +meta_wayland_surface_role_actor_surface_class_init (MetaWaylandSurfaceRoleActorSurfaceClass *klass) +{ + MetaWaylandSurfaceRoleClass *surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (klass); + + surface_role_class->assigned = actor_surface_assigned; + surface_role_class->commit = actor_surface_commit; + surface_role_class->is_on_output = actor_surface_is_on_output; +} + +static void +meta_wayland_surface_role_shell_surface_init (MetaWaylandSurfaceRoleShellSurface *role) +{ +} + +static void +meta_wayland_surface_role_shell_surface_class_init (MetaWaylandSurfaceRoleShellSurfaceClass *klass) +{ +} + static void meta_wayland_surface_role_dnd_init (MetaWaylandSurfaceRoleDND *role) { @@ -2783,54 +2020,6 @@ meta_wayland_surface_role_dnd_class_init (MetaWaylandSurfaceRoleDNDClass *klass) surface_role_class->commit = dnd_surface_commit; } -static void -meta_wayland_surface_role_xdg_surface_init (MetaWaylandSurfaceRoleXdgSurface *role) -{ -} - -static void -meta_wayland_surface_role_xdg_surface_class_init (MetaWaylandSurfaceRoleXdgSurfaceClass *klass) -{ - MetaWaylandSurfaceRoleClass *surface_role_class = - META_WAYLAND_SURFACE_ROLE_CLASS (klass); - - surface_role_class->assigned = actor_surface_assigned; - surface_role_class->commit = toplevel_surface_commit; - surface_role_class->is_on_output = actor_surface_is_on_output; -} - -static void -meta_wayland_surface_role_xdg_popup_init (MetaWaylandSurfaceRoleXdgPopup *role) -{ -} - -static void -meta_wayland_surface_role_xdg_popup_class_init (MetaWaylandSurfaceRoleXdgPopupClass *klass) -{ - MetaWaylandSurfaceRoleClass *surface_role_class = - META_WAYLAND_SURFACE_ROLE_CLASS (klass); - - surface_role_class->assigned = actor_surface_assigned; - surface_role_class->commit = toplevel_surface_commit; - surface_role_class->is_on_output = actor_surface_is_on_output; -} - -static void -meta_wayland_surface_role_wl_shell_surface_init (MetaWaylandSurfaceRoleWlShellSurface *role) -{ -} - -static void -meta_wayland_surface_role_wl_shell_surface_class_init (MetaWaylandSurfaceRoleWlShellSurfaceClass *klass) -{ - MetaWaylandSurfaceRoleClass *surface_role_class = - META_WAYLAND_SURFACE_ROLE_CLASS (klass); - - surface_role_class->assigned = actor_surface_assigned; - surface_role_class->commit = toplevel_surface_commit; - surface_role_class->is_on_output = actor_surface_is_on_output; -} - static void meta_wayland_surface_role_subsurface_init (MetaWaylandSurfaceRoleSubsurface *role) { @@ -2842,9 +2031,7 @@ meta_wayland_surface_role_subsurface_class_init (MetaWaylandSurfaceRoleSubsurfac MetaWaylandSurfaceRoleClass *surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass); - surface_role_class->assigned = actor_surface_assigned; surface_role_class->commit = subsurface_surface_commit; - surface_role_class->is_on_output = actor_surface_is_on_output; } cairo_region_t * diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index c817ed715..cf6b79b35 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -69,29 +69,42 @@ struct _MetaWaylandSerial { uint32_t value; }; +#define META_TYPE_WAYLAND_SURFACE_ROLE_ACTOR_SURFACE (meta_wayland_surface_role_actor_surface_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaWaylandSurfaceRoleActorSurface, + meta_wayland_surface_role_actor_surface, + META, WAYLAND_SURFACE_ROLE_ACTOR_SURFACE, + MetaWaylandSurfaceRole); + +struct _MetaWaylandSurfaceRoleActorSurfaceClass +{ + MetaWaylandSurfaceRoleClass parent_class; +}; + +#define META_TYPE_WAYLAND_SURFACE_ROLE_SHELL_SURFACE (meta_wayland_surface_role_shell_surface_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaWaylandSurfaceRoleShellSurface, + meta_wayland_surface_role_shell_surface, + META, WAYLAND_SURFACE_ROLE_SHELL_SURFACE, + MetaWaylandSurfaceRoleActorSurface); + +struct _MetaWaylandSurfaceRoleShellSurfaceClass +{ + MetaWaylandSurfaceRoleActorSurfaceClass parent_class; + + void (*configure) (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial); + void (*ping) (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + uint32_t serial); + void (*close) (MetaWaylandSurfaceRoleShellSurface *shell_surface_role); + void (*popup_done) (MetaWaylandSurfaceRoleShellSurface *shell_surface_role); +}; + #define META_TYPE_WAYLAND_SURFACE_ROLE_SUBSURFACE (meta_wayland_surface_role_subsurface_get_type ()) G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleSubsurface, meta_wayland_surface_role_subsurface, META, WAYLAND_SURFACE_ROLE_SUBSURFACE, - MetaWaylandSurfaceRole); - -#define META_TYPE_WAYLAND_SURFACE_ROLE_XDG_SURFACE (meta_wayland_surface_role_xdg_surface_get_type ()) -G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleXdgSurface, - meta_wayland_surface_role_xdg_surface, - META, WAYLAND_SURFACE_ROLE_XDG_SURFACE, - MetaWaylandSurfaceRole); - -#define META_TYPE_WAYLAND_SURFACE_ROLE_XDG_POPUP (meta_wayland_surface_role_xdg_popup_get_type ()) -G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleXdgPopup, - meta_wayland_surface_role_xdg_popup, - META, WAYLAND_SURFACE_ROLE_XDG_POPUP, - MetaWaylandSurfaceRole); - -#define META_TYPE_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE (meta_wayland_surface_role_wl_shell_surface_get_type ()) -G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleWlShellSurface, - meta_wayland_surface_role_wl_shell_surface, - META, WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE, - MetaWaylandSurfaceRole); + MetaWaylandSurfaceRoleActorSurface); #define META_TYPE_WAYLAND_SURFACE_ROLE_DND (meta_wayland_surface_role_dnd_get_type ()) G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleDND, @@ -298,4 +311,14 @@ MetaWaylandSurface * meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRo cairo_region_t * meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface); +void meta_wayland_surface_apply_window_state (MetaWaylandSurface *surface, + MetaWaylandPendingState *pending); + +void meta_wayland_surface_destroy_window (MetaWaylandSurface *surface); + +gboolean meta_wayland_surface_begin_grab_op (MetaWaylandSurface *surface, + MetaWaylandSeat *seat, + MetaGrabOp grab_op, + gfloat x, + gfloat y); #endif diff --git a/src/wayland/meta-wayland-wl-shell.c b/src/wayland/meta-wayland-wl-shell.c new file mode 100644 index 000000000..5e0488e59 --- /dev/null +++ b/src/wayland/meta-wayland-wl-shell.c @@ -0,0 +1,448 @@ +/* -*- 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-wl-shell.h" + +#include "core/window-private.h" +#include "wayland/meta-wayland.h" +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-seat.h" +#include "wayland/meta-wayland-surface.h" +#include "wayland/meta-wayland-versions.h" +#include "wayland/meta-window-wayland.h" + +typedef enum +{ + META_WL_SHELL_SURFACE_STATE_NONE, + META_WL_SHELL_SURFACE_STATE_TOPLEVEL, + META_WL_SHELL_SURFACE_STATE_FULLSCREEN, + META_WL_SHELL_SURFACE_STATE_MAXIMIZED, +} MetaWlShellSurfaceState; + +struct _MetaWaylandSurfaceRoleWlShellSurface +{ + MetaWaylandSurfaceRoleShellSurface parent; +}; + +G_DEFINE_TYPE (MetaWaylandSurfaceRoleWlShellSurface, + meta_wayland_surface_role_wl_shell_surface, + META_TYPE_WAYLAND_SURFACE_ROLE_SHELL_SURFACE); + +static void +wl_shell_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, + surface); + surface->wl_shell_surface = NULL; +} + +static void +wl_shell_surface_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 void +wl_shell_surface_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 = wl_resource_get_user_data (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_wl_shell_surface_resize_edge (int edge) +{ + MetaGrabOp op = META_GRAB_OP_WINDOW_BASE; + + if (edge & WL_SHELL_SURFACE_RESIZE_TOP) + op |= META_GRAB_OP_WINDOW_DIR_NORTH; + if (edge & WL_SHELL_SURFACE_RESIZE_BOTTOM) + op |= META_GRAB_OP_WINDOW_DIR_SOUTH; + if (edge & WL_SHELL_SURFACE_RESIZE_LEFT) + op |= META_GRAB_OP_WINDOW_DIR_WEST; + if (edge & WL_SHELL_SURFACE_RESIZE_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 +wl_shell_surface_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 = wl_resource_get_user_data (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_wl_shell_surface_resize_edge (edges); + meta_wayland_surface_begin_grab_op (surface, seat, grab_op, x, y); +} + +static void +wl_shell_surface_set_state (MetaWaylandSurface *surface, + MetaWlShellSurfaceState state) +{ + if (state == META_WL_SHELL_SURFACE_STATE_FULLSCREEN) + meta_window_make_fullscreen (surface->window); + else + meta_window_unmake_fullscreen (surface->window); + + if (state == META_WL_SHELL_SURFACE_STATE_MAXIMIZED) + meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); + else + meta_window_unmaximize (surface->window, META_MAXIMIZE_BOTH); +} + +static void +wl_shell_surface_set_toplevel (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, + META_WL_SHELL_SURFACE_STATE_TOPLEVEL); +} + +static void +wl_shell_surface_set_transient (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *parent_resource, + int32_t x, + int32_t y, + uint32_t flags) +{ + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, + META_WL_SHELL_SURFACE_STATE_TOPLEVEL); + + meta_window_set_transient_for (surface->window, parent_surf->window); + meta_window_wayland_place_relative_to (surface->window, + parent_surf->window, + x, y); +} + +static void +wl_shell_surface_set_fullscreen (struct wl_client *client, + struct wl_resource *resource, + uint32_t method, + uint32_t framerate, + struct wl_resource *output) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, + META_WL_SHELL_SURFACE_STATE_FULLSCREEN); +} + +static void +handle_wl_shell_popup_parent_destroyed (struct wl_listener *listener, + void *data) +{ + MetaWaylandSurface *surface = + wl_container_of (listener, surface, popup.parent_destroy_listener); + + wl_list_remove (&surface->popup.parent_destroy_listener.link); + surface->popup.parent = NULL; +} + +static void +wl_shell_surface_set_popup (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + uint32_t serial, + struct wl_resource *parent_resource, + int32_t x, + int32_t y, + uint32_t flags) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + + wl_shell_surface_set_state (surface, + META_WL_SHELL_SURFACE_STATE_TOPLEVEL); + + if (!meta_wayland_seat_can_popup (seat, serial)) + { + wl_shell_surface_send_popup_done (resource); + return; + } + + meta_window_set_transient_for (surface->window, parent_surf->window); + meta_window_wayland_place_relative_to (surface->window, + parent_surf->window, + x, y); + + if (!surface->popup.parent) + { + surface->popup.parent = parent_surf; + surface->popup.parent_destroy_listener.notify = + handle_wl_shell_popup_parent_destroyed; + wl_resource_add_destroy_listener (parent_surf->resource, + &surface->popup.parent_destroy_listener); + } + + meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); +} + +static void +wl_shell_surface_set_maximized (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *output) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + wl_shell_surface_set_state (surface, + META_WL_SHELL_SURFACE_STATE_MAXIMIZED); +} + +static void +wl_shell_surface_set_title (struct wl_client *client, + struct wl_resource *resource, + const char *title) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_title (surface->window, title); +} + +static void +wl_shell_surface_set_class (struct wl_client *client, + struct wl_resource *resource, + const char *class_) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_wm_class (surface->window, class_, class_); +} + +static const struct wl_shell_surface_interface meta_wayland_wl_shell_surface_interface = { + wl_shell_surface_pong, + wl_shell_surface_move, + wl_shell_surface_resize, + wl_shell_surface_set_toplevel, + wl_shell_surface_set_transient, + wl_shell_surface_set_fullscreen, + wl_shell_surface_set_popup, + wl_shell_surface_set_maximized, + wl_shell_surface_set_title, + wl_shell_surface_set_class, +}; + +static void +wl_shell_get_shell_surface (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWindow *window; + + if (surface->wl_shell_surface != NULL) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "wl_shell::get_shell_surface already requested"); + return; + } + + if (!meta_wayland_surface_assign_role (surface, + META_TYPE_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE)) + { + wl_resource_post_error (resource, WL_SHELL_ERROR_ROLE, + "wl_surface@%d already has a different role", + wl_resource_get_id (surface->resource)); + return; + } + + surface->wl_shell_surface = wl_resource_create (client, + &wl_shell_surface_interface, + wl_resource_get_version (resource), + id); + wl_resource_set_implementation (surface->wl_shell_surface, + &meta_wayland_wl_shell_surface_interface, + surface, + wl_shell_surface_destructor); + + window = meta_window_wayland_new (meta_get_display (), surface); + meta_wayland_surface_set_window (surface, window); +} + +static const struct wl_shell_interface meta_wayland_wl_shell_interface = { + wl_shell_get_shell_surface, +}; + +static void +bind_wl_shell (struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, &wl_shell_interface, version, id); + wl_resource_set_implementation (resource, &meta_wayland_wl_shell_interface, data, NULL); +} + +static void +wl_shell_surface_role_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandPendingState *pending) +{ + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + MetaWindow *window = surface->window; + + surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_wl_shell_surface_parent_class); + surface_role_class->commit (surface_role, pending); + + /* For wl_shell, it's equivalent to an unmap. Semantics + * are poorly defined, so we can choose some that are + * convenient for us. */ + if (surface->buffer_ref.buffer && !window) + { + window = meta_window_wayland_new (meta_get_display (), surface); + meta_wayland_surface_set_window (surface, window); + } + else if (!surface->buffer_ref.buffer && window) + { + meta_wayland_surface_destroy_window (surface); + return; + } + + if (pending->newly_attached) + meta_wayland_surface_apply_window_state (surface, pending); +} + +static void +wl_shell_surface_role_configure (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial) +{ + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (shell_surface_role); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + if (!surface->wl_shell_surface) + return; + + wl_shell_surface_send_configure (surface->wl_shell_surface, + 0, + new_width, new_height); +} + +static void +wl_shell_surface_role_ping (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + guint32 serial) +{ + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (shell_surface_role); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + wl_shell_surface_send_ping (surface->wl_shell_surface, serial); +} + +static void +wl_shell_surface_role_close (MetaWaylandSurfaceRoleShellSurface *shell_surface_role) +{ + /* Not supported by wl_shell_surface. */ +} + +static void +wl_shell_surface_role_popup_done (MetaWaylandSurfaceRoleShellSurface *shell_surface_role) +{ + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (shell_surface_role); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + wl_shell_surface_send_popup_done (surface->wl_shell_surface); +} + +static void +meta_wayland_surface_role_wl_shell_surface_init (MetaWaylandSurfaceRoleWlShellSurface *role) +{ +} + +static void +meta_wayland_surface_role_wl_shell_surface_class_init (MetaWaylandSurfaceRoleWlShellSurfaceClass *klass) +{ + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurfaceRoleShellSurfaceClass *shell_surface_role_class; + + surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass); + surface_role_class->commit = wl_shell_surface_role_commit; + + shell_surface_role_class = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE_CLASS (klass); + shell_surface_role_class->configure = wl_shell_surface_role_configure; + shell_surface_role_class->ping = wl_shell_surface_role_ping; + shell_surface_role_class->close = wl_shell_surface_role_close; + shell_surface_role_class->popup_done = wl_shell_surface_role_popup_done; +} + +void +meta_wayland_wl_shell_init (MetaWaylandCompositor *compositor) +{ + if (wl_global_create (compositor->wayland_display, + &wl_shell_interface, + META_WL_SHELL_VERSION, + compositor, bind_wl_shell) == NULL) + g_error ("Failed to register a global wl-shell object"); +} diff --git a/src/wayland/meta-wayland-wl-shell.h b/src/wayland/meta-wayland-wl-shell.h new file mode 100644 index 000000000..3ceec6685 --- /dev/null +++ b/src/wayland/meta-wayland-wl-shell.h @@ -0,0 +1,33 @@ +/* + * 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_WL_SHELL_H +#define META_WAYLAND_WL_SHELL_H + +#include "wayland/meta-wayland-surface.h" + +#define META_TYPE_WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE (meta_wayland_surface_role_wl_shell_surface_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleWlShellSurface, + meta_wayland_surface_role_wl_shell_surface, + META, WAYLAND_SURFACE_ROLE_WL_SHELL_SURFACE, + MetaWaylandSurfaceRoleShellSurface); + +void meta_wayland_wl_shell_init (MetaWaylandCompositor *compositor); + +#endif /* META_WAYLAND_WL_SHELL_H */ diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c new file mode 100644 index 000000000..cf1c7c7b3 --- /dev/null +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -0,0 +1,759 @@ +/* -*- 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-xdg-shell.h" + +#include "core/window-private.h" +#include "wayland/meta-wayland.h" +#include "wayland/meta-wayland-popup.h" +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-seat.h" +#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" + +struct _MetaWaylandSurfaceRoleXdgSurface +{ + MetaWaylandSurfaceRoleShellSurface parent; +}; + +G_DEFINE_TYPE (MetaWaylandSurfaceRoleXdgSurface, + meta_wayland_surface_role_xdg_surface, + META_TYPE_WAYLAND_SURFACE_ROLE_SHELL_SURFACE); + +struct _MetaWaylandSurfaceRoleXdgPopup +{ + MetaWaylandSurfaceRoleShellSurface parent; +}; + +G_DEFINE_TYPE (MetaWaylandSurfaceRoleXdgPopup, + meta_wayland_surface_role_xdg_popup, + META_TYPE_WAYLAND_SURFACE_ROLE_SHELL_SURFACE); + +static void +xdg_shell_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +xdg_shell_use_unstable_version (struct wl_client *client, + struct wl_resource *resource, + int32_t version) +{ + if (version != XDG_SHELL_VERSION_CURRENT) + wl_resource_post_error (resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "bad xdg-shell version: %d\n", version); +} + +static void +xdg_shell_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 void +xdg_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, + surface); + meta_wayland_surface_destroy_window (surface); + surface->xdg_surface = NULL; +} + +static void +xdg_surface_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) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWindow *transient_for = NULL; + + if (parent_resource) + { + MetaWaylandSurface *parent_surface = + wl_resource_get_user_data (parent_resource); + transient_for = parent_surface->window; + } + + meta_window_set_transient_for (surface->window, transient_for); +} + +static void +xdg_surface_set_title (struct wl_client *client, + struct wl_resource *resource, + const char *title) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_title (surface->window, title); +} + +static void +xdg_surface_set_app_id (struct wl_client *client, + struct wl_resource *resource, + const char *app_id) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_set_wm_class (surface->window, app_id, app_id); +} + +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) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (!meta_wayland_seat_get_grab_info (seat, surface, serial, FALSE, NULL, NULL)) + return; + + meta_window_show_menu (surface->window, META_WINDOW_MENU_WM, + surface->window->buffer_rect.x + x, + surface->window->buffer_rect.y + y); +} + +static void +xdg_surface_move (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + guint32 serial) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (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_surface_resize_edge (int edge) +{ + MetaGrabOp op = META_GRAB_OP_WINDOW_BASE; + + if (edge & XDG_SURFACE_RESIZE_EDGE_TOP) + op |= META_GRAB_OP_WINDOW_DIR_NORTH; + if (edge & XDG_SURFACE_RESIZE_EDGE_BOTTOM) + op |= META_GRAB_OP_WINDOW_DIR_SOUTH; + if (edge & XDG_SURFACE_RESIZE_EDGE_LEFT) + op |= META_GRAB_OP_WINDOW_DIR_WEST; + if (edge & XDG_SURFACE_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 +xdg_surface_resize (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *seat_resource, + guint32 serial, + guint32 edges) +{ + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWaylandSurface *surface = wl_resource_get_user_data (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); + meta_wayland_surface_begin_grab_op (surface, seat, grab_op, x, y); +} + +static void +xdg_surface_ack_configure (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + surface->acked_configure_serial.set = TRUE; + surface->acked_configure_serial.value = serial; +} + +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 = wl_resource_get_user_data (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_set_maximized (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_maximize (surface->window, META_MAXIMIZE_BOTH); +} + +static void +xdg_surface_unset_maximized (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (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) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_make_fullscreen (surface->window); +} + +static void +xdg_surface_unset_fullscreen (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_window_unmake_fullscreen (surface->window); +} + +static void +xdg_surface_set_minimized (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (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 void +xdg_shell_get_xdg_surface (struct wl_client *client, + struct wl_resource *resource, + guint32 id, + struct wl_resource *surface_resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWindow *window; + + if (surface->xdg_surface != NULL) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "xdg_shell::get_xdg_surface already requested"); + return; + } + + if (!meta_wayland_surface_assign_role (surface, + META_TYPE_WAYLAND_SURFACE_ROLE_XDG_SURFACE)) + { + wl_resource_post_error (resource, XDG_SHELL_ERROR_ROLE, + "wl_surface@%d already has a different role", + wl_resource_get_id (surface->resource)); + return; + } + + surface->xdg_surface = wl_resource_create (client, + &xdg_surface_interface, + wl_resource_get_version (resource), + id); + wl_resource_set_implementation (surface->xdg_surface, + &meta_wayland_xdg_surface_interface, + surface, + xdg_surface_destructor); + + surface->xdg_shell_resource = resource; + + window = meta_window_wayland_new (meta_get_display (), surface); + meta_wayland_surface_set_window (surface, window); +} + +static void +xdg_popup_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, + surface); + if (surface->popup.parent) + { + wl_list_remove (&surface->popup.parent_destroy_listener.link); + surface->popup.parent = NULL; + } + + if (surface->popup.popup) + meta_wayland_popup_dismiss (surface->popup.popup); + + surface->xdg_popup = NULL; +} + +static void +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 = { + xdg_popup_destroy, +}; + +static void +handle_popup_parent_destroyed (struct wl_listener *listener, + void *data) +{ + MetaWaylandSurface *surface = + wl_container_of (listener, surface, popup.parent_destroy_listener); + + wl_resource_post_error (surface->xdg_shell_resource, + XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, + "destroyed popup not top most popup"); + surface->popup.parent = NULL; + + meta_wayland_surface_destroy_window (surface); +} + +static void +handle_popup_destroyed (struct wl_listener *listener, + void *data) +{ + MetaWaylandPopup *popup = data; + MetaWaylandSurface *top_popup; + MetaWaylandSurface *surface = + wl_container_of (listener, surface, popup.destroy_listener); + + top_popup = meta_wayland_popup_get_top_popup (popup); + if (surface != top_popup) + { + wl_resource_post_error (surface->xdg_shell_resource, + XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, + "destroyed popup not top most popup"); + } + + surface->popup.popup = NULL; + + meta_wayland_surface_destroy_window (surface); +} + +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) +{ + struct wl_resource *popup_resource; + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSurface *top_popup; + MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); + MetaWindow *window; + MetaDisplay *display = meta_get_display (); + MetaWaylandPopup *popup; + + if (surface->xdg_popup != NULL) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "xdg_shell::get_xdg_popup already requested"); + return; + } + + if (!meta_wayland_surface_assign_role (surface, + META_TYPE_WAYLAND_SURFACE_ROLE_XDG_POPUP)) + { + wl_resource_post_error (resource, XDG_SHELL_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 || + (parent_surf->xdg_popup == NULL && parent_surf->xdg_surface == NULL)) + { + wl_resource_post_error (resource, + XDG_SHELL_ERROR_INVALID_POPUP_PARENT, + "invalid parent surface"); + return; + } + + top_popup = meta_wayland_pointer_get_top_popup (&seat->pointer); + if ((top_popup == NULL && parent_surf->xdg_surface == NULL) || + (top_popup != NULL && parent_surf != top_popup)) + { + wl_resource_post_error (resource, + XDG_SHELL_ERROR_NOT_THE_TOPMOST_POPUP, + "parent not top most surface"); + return; + } + + popup_resource = wl_resource_create (client, &xdg_popup_interface, + wl_resource_get_version (resource), id); + wl_resource_set_implementation (popup_resource, + &meta_wayland_xdg_popup_interface, + surface, + xdg_popup_destructor); + + surface->xdg_popup = popup_resource; + surface->xdg_shell_resource = resource; + + if (!meta_wayland_seat_can_popup (seat, serial)) + { + xdg_popup_send_popup_done (popup_resource); + return; + } + + surface->popup.parent = parent_surf; + surface->popup.parent_destroy_listener.notify = handle_popup_parent_destroyed; + wl_resource_add_destroy_listener (parent_surf->resource, + &surface->popup.parent_destroy_listener); + + 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; + + meta_wayland_surface_set_window (surface, window); + + meta_window_focus (window, meta_display_get_current_time (display)); + popup = meta_wayland_pointer_start_popup_grab (&seat->pointer, surface); + if (popup == NULL) + { + meta_wayland_surface_destroy_window (surface); + return; + } + + surface->popup.destroy_listener.notify = handle_popup_destroyed; + surface->popup.popup = popup; + wl_signal_add (meta_wayland_popup_get_destroy_signal (popup), + &surface->popup.destroy_listener); +} + +static const struct xdg_shell_interface meta_wayland_xdg_shell_interface = { + xdg_shell_destroy, + xdg_shell_use_unstable_version, + xdg_shell_get_xdg_surface, + xdg_shell_get_xdg_popup, + xdg_shell_pong, +}; + +static void +bind_xdg_shell (struct wl_client *client, + void *data, + guint32 version, + guint32 id) +{ + struct wl_resource *resource; + + if (version != META_XDG_SHELL_VERSION) + { + g_warning ("using xdg-shell without stable version %d\n", + META_XDG_SHELL_VERSION); + return; + } + + resource = wl_resource_create (client, &xdg_shell_interface, version, id); + wl_resource_set_implementation (resource, &meta_wayland_xdg_shell_interface, + data, NULL); +} + +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 = XDG_SURFACE_STATE_MAXIMIZED; + } + if (meta_window_is_fullscreen (window)) + { + s = wl_array_add (states, sizeof *s); + *s = XDG_SURFACE_STATE_FULLSCREEN; + } + if (meta_grab_op_is_resizing (window->display->grab_op)) + { + s = wl_array_add (states, sizeof *s); + *s = XDG_SURFACE_STATE_RESIZING; + } + if (meta_window_appears_focused (window)) + { + s = wl_array_add (states, sizeof *s); + *s = XDG_SURFACE_STATE_ACTIVATED; + } +} + +static void +xdg_surface_role_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandPendingState *pending) +{ + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_xdg_surface_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_surface"); + return; + } + + if (pending->newly_attached) + meta_wayland_surface_apply_window_state (surface, pending); +} + +static void +xdg_surface_role_configure (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial) +{ + 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 (surface->xdg_surface); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + struct wl_array states; + + if (!surface->xdg_surface) + return; + + wl_array_init (&states); + fill_states (&states, surface->window); + + xdg_surface_send_configure (surface->xdg_surface, + new_width, new_height, + &states, + serial); + + wl_array_release (&states); + + if (sent_serial) + { + sent_serial->set = TRUE; + sent_serial->value = serial; + } +} + +static void +xdg_surface_role_ping (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + uint32_t serial) +{ + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (shell_surface_role); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + xdg_shell_send_ping (surface->xdg_shell_resource, serial); +} + +static void +xdg_surface_role_close (MetaWaylandSurfaceRoleShellSurface *shell_surface_role) +{ + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (shell_surface_role); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + xdg_surface_send_close (surface->xdg_surface); +} + +static void +meta_wayland_surface_role_xdg_surface_init (MetaWaylandSurfaceRoleXdgSurface *role) +{ +} + +static void +meta_wayland_surface_role_xdg_surface_class_init (MetaWaylandSurfaceRoleXdgSurfaceClass *klass) +{ + MetaWaylandSurfaceRoleClass *surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (klass); + + surface_role_class->commit = xdg_surface_role_commit; + + MetaWaylandSurfaceRoleShellSurfaceClass *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->ping = xdg_surface_role_ping; + shell_surface_role_class->close = xdg_surface_role_close; +} + +static void +xdg_popup_role_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandPendingState *pending) +{ + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_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) + meta_wayland_surface_apply_window_state (surface, pending); +} + +static void +xdg_popup_role_configure (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + int new_width, + int new_height, + MetaWaylandSerial *sent_serial) +{ + /* This can happen if the popup window loses or receives focus. + * Just ignore it. */ +} + +static void +xdg_popup_role_ping (MetaWaylandSurfaceRoleShellSurface *shell_surface_role, + uint32_t serial) +{ + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (shell_surface_role); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + xdg_shell_send_ping (surface->xdg_shell_resource, serial); +} + +static void +xdg_popup_role_popup_done (MetaWaylandSurfaceRoleShellSurface *shell_surface_role) +{ + MetaWaylandSurfaceRole *surface_role = + META_WAYLAND_SURFACE_ROLE (shell_surface_role); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + + xdg_popup_send_popup_done (surface->xdg_popup); +} + +static void +meta_wayland_surface_role_xdg_popup_init (MetaWaylandSurfaceRoleXdgPopup *role) +{ +} + +static void +meta_wayland_surface_role_xdg_popup_class_init (MetaWaylandSurfaceRoleXdgPopupClass *klass) +{ + MetaWaylandSurfaceRoleClass *surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (klass); + + surface_role_class->commit = xdg_popup_role_commit; + + MetaWaylandSurfaceRoleShellSurfaceClass *shell_surface_role_class = + META_WAYLAND_SURFACE_ROLE_SHELL_SURFACE_CLASS (klass); + + shell_surface_role_class->configure = xdg_popup_role_configure; + shell_surface_role_class->ping = xdg_popup_role_ping; + shell_surface_role_class->popup_done = xdg_popup_role_popup_done; +} + +void +meta_wayland_xdg_shell_init (MetaWaylandCompositor *compositor) +{ + if (wl_global_create (compositor->wayland_display, + &xdg_shell_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 new file mode 100644 index 000000000..28742ff59 --- /dev/null +++ b/src/wayland/meta-wayland-xdg-shell.h @@ -0,0 +1,39 @@ +/* + * 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_XDG_SHELL_H +#define META_WAYLAND_XDG_SHELL_H + +#include "wayland/meta-wayland-surface.h" + +#define META_TYPE_WAYLAND_SURFACE_ROLE_XDG_SURFACE (meta_wayland_surface_role_xdg_surface_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleXdgSurface, + meta_wayland_surface_role_xdg_surface, + META, WAYLAND_SURFACE_ROLE_XDG_SURFACE, + MetaWaylandSurfaceRoleShellSurface); + +#define META_TYPE_WAYLAND_SURFACE_ROLE_XDG_POPUP (meta_wayland_surface_role_xdg_popup_get_type ()) +G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleXdgPopup, + meta_wayland_surface_role_xdg_popup, + META, WAYLAND_SURFACE_ROLE_XDG_POPUP, + MetaWaylandSurfaceRoleShellSurface); + +void meta_wayland_xdg_shell_init (MetaWaylandCompositor *compositor); + +#endif /* META_WAYLAND_XDG_SHELL_H */ diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c index f38e4b984..fb051a1e0 100644 --- a/src/wayland/meta-window-wayland.c +++ b/src/wayland/meta-window-wayland.c @@ -32,6 +32,7 @@ #include "stack-tracker.h" #include "meta-wayland-private.h" #include "meta-wayland-surface.h" +#include "meta-wayland-xdg-shell.h" #include "compositor/meta-surface-actor-wayland.h" struct _MetaWindowWayland