diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index 21e41bb80..e0c9ad21a 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -49,7 +49,6 @@ #include "meta-wayland-pointer.h" #include "meta-wayland-private.h" -#include "xdg-shell-server-protocol.h" #include @@ -530,14 +529,7 @@ meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer) wl_list_for_each_safe (popup, tmp, &popup_grab->all_popups, link) { - MetaWaylandSurfaceExtension *xdg_popup = &popup->surface->xdg_popup; - struct wl_client *client = wl_resource_get_client (xdg_popup->resource); - struct wl_display *display = wl_client_get_display (client); - uint32_t serial; - - serial = wl_display_next_serial (display); - - xdg_popup_send_popup_done (xdg_popup->resource, serial); + meta_wayland_surface_popup_done (popup->surface); wl_list_remove (&popup->surface_destroy_listener.link); wl_list_remove (&popup->link); g_slice_free (MetaWaylandPopup, popup); @@ -597,7 +589,10 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer, popup->grab = grab; popup->surface = surface; popup->surface_destroy_listener.notify = on_popup_surface_destroy; - wl_resource_add_destroy_listener (surface->xdg_popup.resource, &popup->surface_destroy_listener); + if (surface->xdg_popup.resource) + wl_resource_add_destroy_listener (surface->xdg_popup.resource, &popup->surface_destroy_listener); + else if (surface->wl_shell_surface.resource) + wl_resource_add_destroy_listener (surface->wl_shell_surface.resource, &popup->surface_destroy_listener); wl_list_insert (&grab->all_popups, &popup->link); diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 0c5c7115f..0c671048f 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -825,7 +825,7 @@ xdg_surface_move (struct wl_client *client, } static MetaGrabOp -grab_op_for_edge (int edge) +grab_op_for_xdg_surface_resize_edge (int edge) { switch (edge) { @@ -867,7 +867,7 @@ xdg_surface_resize (struct wl_client *client, seat->pointer.focus_surface != surface) return; - begin_grab_op_on_surface (surface, seat, grab_op_for_edge (edges)); + begin_grab_op_on_surface (surface, seat, grab_op_for_xdg_surface_resize_edge (edges)); } static void @@ -1099,6 +1099,267 @@ bind_xdg_shell (struct wl_client *client, wl_client_add_destroy_listener (client, &xdg_shell->client_destroy_listener); } +static void +wl_shell_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + + destroy_surface_extension (wl_shell_surface); +} + +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); + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, META_GRAB_OP_MOVING); +} + +static MetaGrabOp +grab_op_for_wl_shell_surface_resize_edge (int edge) +{ + switch (edge) + { + case WL_SHELL_SURFACE_RESIZE_TOP_LEFT: + return META_GRAB_OP_RESIZING_NW; + case WL_SHELL_SURFACE_RESIZE_TOP: + return META_GRAB_OP_RESIZING_N; + case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: + return META_GRAB_OP_RESIZING_NE; + case WL_SHELL_SURFACE_RESIZE_RIGHT: + return META_GRAB_OP_RESIZING_E; + case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: + return META_GRAB_OP_RESIZING_SE; + case WL_SHELL_SURFACE_RESIZE_BOTTOM: + return META_GRAB_OP_RESIZING_S; + case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: + return META_GRAB_OP_RESIZING_SW; + case WL_SHELL_SURFACE_RESIZE_LEFT: + return META_GRAB_OP_RESIZING_W; + default: + g_warning ("invalid edge: %d", edge); + return META_GRAB_OP_NONE; + } +} + +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); + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + + if (seat->pointer.button_count == 0 || + seat->pointer.grab_serial != serial || + seat->pointer.focus_surface != surface) + return; + + begin_grab_op_on_surface (surface, seat, grab_op_for_wl_shell_surface_resize_edge (edges)); +} + +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_VERTICAL | META_MAXIMIZE_HORIZONTAL); + else + meta_window_unmaximize (surface->window, META_MAXIMIZE_VERTICAL | META_MAXIMIZE_HORIZONTAL); +} + +static void +wl_shell_surface_set_toplevel (struct wl_client *client, + struct wl_resource *resource) +{ + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + + 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) +{ + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + + wl_shell_surface_set_state (surface, SURFACE_STATE_TOPLEVEL); + + meta_window_set_transient_for (surface->window, parent_surf->window); + meta_window_move (surface->window, FALSE, + parent_surf->window->rect.x + x, + parent_surf->window->rect.y + y); + surface->window->placed = TRUE; +} + +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) +{ + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + + wl_shell_surface_set_state (surface, SURFACE_STATE_FULLSCREEN); +} + +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) +{ + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + 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); + + meta_window_set_transient_for (surface->window, parent_surf->window); + meta_window_move (surface->window, FALSE, + parent_surf->window->rect.x + x, + parent_surf->window->rect.y + y); + surface->window->placed = TRUE; + + 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) +{ + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + + 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) +{ + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + + 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_) +{ + MetaWaylandSurfaceExtension *wl_shell_surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = wl_container_of (wl_shell_surface, surface, wl_shell_surface); + + 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); + + if (!create_surface_extension (&surface->wl_shell_surface, client, surface_resource, resource, id, + META_WL_SHELL_SURFACE_VERSION, + &wl_shell_surface_interface, + &meta_wayland_wl_shell_surface_interface, + wl_shell_surface_destructor)) + { + wl_resource_post_error (surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "wl_shell::get_shell_surface already requested"); + return; + } + + meta_wayland_surface_make_toplevel (surface); + surface->window = meta_window_wayland_new (meta_get_display (), surface); +} + +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, + MIN (META_WL_SHELL_VERSION, version), id); + wl_resource_set_implementation (resource, &meta_wayland_wl_shell_interface, data, NULL); +} + static void gtk_surface_destructor (struct wl_resource *resource) { @@ -1486,6 +1747,11 @@ meta_wayland_init_shell (MetaWaylandCompositor *compositor) 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, 1, + compositor, bind_wl_shell) == NULL) + g_error ("Failed to register a global wl-shell object"); + if (wl_global_create (compositor->wayland_display, >k_shell_interface, META_GTK_SHELL_VERSION, @@ -1507,6 +1773,9 @@ meta_wayland_surface_configure_notify (MetaWaylandSurface *surface, if (surface->xdg_surface.resource) xdg_surface_send_configure (surface->xdg_surface.resource, new_width, new_height); + else if (surface->wl_shell_surface.resource) + wl_shell_surface_send_configure (surface->wl_shell_surface.resource, + 0, new_width, new_height); } void @@ -1527,16 +1796,23 @@ void meta_wayland_surface_ping (MetaWaylandSurface *surface, guint32 serial) { - struct wl_client *client = wl_resource_get_client (surface->resource); - struct wl_resource *xdg_shell = get_xdg_shell_for_client (client); - - if (xdg_shell == NULL) + if (surface->xdg_surface.resource) { - g_warning ("Trying to ping a surface without an xdg_shell bound. How does this happen?"); - return; - } + struct wl_client *client = wl_resource_get_client (surface->resource); + struct wl_resource *xdg_shell = get_xdg_shell_for_client (client); - xdg_shell_send_ping (xdg_shell, serial); + if (xdg_shell == NULL) + { + g_warning ("Trying to ping a surface without an xdg_shell bound. How does this happen?"); + return; + } + + xdg_shell_send_ping (xdg_shell, serial); + } + else if (surface->wl_shell_surface.resource) + { + wl_shell_surface_send_ping (surface->wl_shell_surface.resource, serial); + } } void @@ -1545,3 +1821,16 @@ meta_wayland_surface_delete (MetaWaylandSurface *surface) if (surface->xdg_surface.resource) xdg_surface_send_delete (surface->xdg_surface.resource); } + +void +meta_wayland_surface_popup_done (MetaWaylandSurface *surface) +{ + struct wl_client *client = wl_resource_get_client (surface->resource); + struct wl_display *display = wl_client_get_display (client); + uint32_t serial = wl_display_next_serial (display); + + if (surface->xdg_popup.resource) + xdg_popup_send_popup_done (surface->xdg_popup.resource, serial); + else if (surface->wl_shell_surface.resource) + wl_shell_surface_send_popup_done (surface->wl_shell_surface.resource); +} diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 9e12451d4..e0203f58c 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -86,6 +86,7 @@ struct _MetaWaylandSurface MetaWindow *window; MetaWaylandSurfaceExtension xdg_surface; MetaWaylandSurfaceExtension xdg_popup; + MetaWaylandSurfaceExtension wl_shell_surface; MetaWaylandSurfaceExtension gtk_surface; MetaWaylandSurfaceExtension subsurface; @@ -132,4 +133,7 @@ void meta_wayland_surface_ping (MetaWaylandSurface *surface, guint32 serial); void meta_wayland_surface_delete (MetaWaylandSurface *surface); +void meta_wayland_surface_popup_done (MetaWaylandSurface *surface); + + #endif diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h index e2d608c86..17d8895eb 100644 --- a/src/wayland/meta-wayland-versions.h +++ b/src/wayland/meta-wayland-versions.h @@ -37,6 +37,7 @@ /* Global/master objects (version exported by wl_registry and negotiated through bind) */ #define META_WL_COMPOSITOR_VERSION 3 #define META_WL_DATA_DEVICE_MANAGER_VERSION 1 +#define META_WL_SHELL_VERSION 1 #define META_WL_SEAT_VERSION 2 /* 3 not implemented yet */ #define META_WL_OUTPUT_VERSION 2 #define META_XSERVER_VERSION 1 @@ -52,9 +53,10 @@ #define META_WL_KEYBOARD_VERSION 2 /* from wl_seat; 3 not implemented yet */ #define META_WL_TOUCH_VERSION 0 /* from wl_seat; wl_touch not supported */ #define META_WL_REGION_VERSION 1 /* from wl_compositor */ -#define META_GTK_SURFACE_VERSION 1 /* from gtk_shell */ #define META_XDG_SURFACE_VERSION 1 /* from xdg_shell */ #define META_XDG_POPUP_VERSION 1 /* from xdg_shell */ +#define META_WL_SHELL_SURFACE_VERSION 1 /* from wl_shell */ +#define META_GTK_SURFACE_VERSION 1 /* from gtk_shell */ #define META_WL_SUBSURFACE_VERSION 1 /* from wl_subcompositor */ /* The first version to implement a specific event */