451 lines
18 KiB
C++
451 lines
18 KiB
C++
// Copyright 2018 The ChromiumOS Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "sommelier.h" // NOLINT(build/include_directory)
|
|
#include "sommelier-transform.h" // NOLINT(build/include_directory)
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "xdg-shell-client-protocol.h" // NOLINT(build/include_directory)
|
|
#include "xdg-shell-server-protocol.h" // NOLINT(build/include_directory)
|
|
|
|
struct sl_host_xdg_shell {
|
|
struct sl_context* ctx;
|
|
struct wl_resource* resource;
|
|
struct xdg_wm_base* proxy;
|
|
};
|
|
MAP_STRUCTS(xdg_wm_base, sl_host_xdg_shell);
|
|
|
|
struct sl_host_xdg_surface {
|
|
struct sl_context* ctx;
|
|
struct wl_resource* resource;
|
|
struct xdg_surface* proxy;
|
|
struct sl_host_surface* originator;
|
|
};
|
|
MAP_STRUCTS(xdg_surface, sl_host_xdg_surface);
|
|
|
|
struct sl_host_xdg_toplevel {
|
|
struct sl_context* ctx;
|
|
struct wl_resource* resource;
|
|
struct xdg_toplevel* proxy;
|
|
struct sl_host_xdg_surface* originator;
|
|
};
|
|
MAP_STRUCTS(xdg_toplevel, sl_host_xdg_toplevel);
|
|
|
|
struct sl_host_xdg_popup {
|
|
struct sl_context* ctx;
|
|
struct wl_resource* resource;
|
|
struct xdg_popup* proxy;
|
|
struct sl_host_xdg_surface* originator;
|
|
};
|
|
MAP_STRUCTS(xdg_popup, sl_host_xdg_popup);
|
|
|
|
struct sl_host_xdg_positioner {
|
|
struct sl_context* ctx;
|
|
struct wl_resource* resource;
|
|
struct xdg_positioner* proxy;
|
|
};
|
|
MAP_STRUCTS(xdg_positioner, sl_host_xdg_positioner);
|
|
|
|
static void sl_xdg_positioner_destroy(struct wl_client* client,
|
|
struct wl_resource* resource) {
|
|
wl_resource_destroy(resource);
|
|
}
|
|
|
|
static void sl_xdg_positioner_set_size(struct wl_client* client,
|
|
struct wl_resource* resource,
|
|
int32_t width,
|
|
int32_t height) {
|
|
struct sl_host_xdg_positioner* host =
|
|
static_cast<sl_host_xdg_positioner*>(wl_resource_get_user_data(resource));
|
|
|
|
int32_t iwidth = width;
|
|
int32_t iheight = height;
|
|
|
|
sl_transform_guest_to_host(host->ctx, nullptr, &iwidth, &iheight);
|
|
xdg_positioner_set_size(host->proxy, iwidth, iheight);
|
|
}
|
|
|
|
static void sl_xdg_positioner_set_anchor_rect(struct wl_client* client,
|
|
struct wl_resource* resource,
|
|
int32_t x,
|
|
int32_t y,
|
|
int32_t width,
|
|
int32_t height) {
|
|
struct sl_host_xdg_positioner* host =
|
|
static_cast<sl_host_xdg_positioner*>(wl_resource_get_user_data(resource));
|
|
int32_t x1 = x;
|
|
int32_t y1 = y;
|
|
int32_t x2 = x + width;
|
|
int32_t y2 = y + height;
|
|
|
|
sl_transform_guest_to_host(host->ctx, nullptr, &x1, &y1);
|
|
sl_transform_guest_to_host(host->ctx, nullptr, &x2, &y2);
|
|
|
|
xdg_positioner_set_anchor_rect(host->proxy, x1, y1, x2 - x1, y2 - y1);
|
|
}
|
|
|
|
static void sl_xdg_positioner_set_offset(struct wl_client* client,
|
|
struct wl_resource* resource,
|
|
int32_t x,
|
|
int32_t y) {
|
|
struct sl_host_xdg_positioner* host =
|
|
static_cast<sl_host_xdg_positioner*>(wl_resource_get_user_data(resource));
|
|
int32_t ix = x, iy = y;
|
|
|
|
sl_transform_guest_to_host(host->ctx, nullptr, &ix, &iy);
|
|
xdg_positioner_set_offset(host->proxy, ix, iy);
|
|
}
|
|
|
|
static const struct xdg_positioner_interface sl_xdg_positioner_implementation =
|
|
{sl_xdg_positioner_destroy,
|
|
sl_xdg_positioner_set_size,
|
|
sl_xdg_positioner_set_anchor_rect,
|
|
ForwardRequest<xdg_positioner_set_anchor>,
|
|
ForwardRequest<xdg_positioner_set_gravity>,
|
|
ForwardRequest<xdg_positioner_set_constraint_adjustment>,
|
|
sl_xdg_positioner_set_offset};
|
|
|
|
static void sl_destroy_host_xdg_positioner(struct wl_resource* resource) {
|
|
struct sl_host_xdg_positioner* host =
|
|
static_cast<sl_host_xdg_positioner*>(wl_resource_get_user_data(resource));
|
|
|
|
xdg_positioner_destroy(host->proxy);
|
|
wl_resource_set_user_data(resource, NULL);
|
|
delete host;
|
|
}
|
|
|
|
static void sl_xdg_popup_destroy(struct wl_client* client,
|
|
struct wl_resource* resource) {
|
|
wl_resource_destroy(resource);
|
|
}
|
|
|
|
static const struct xdg_popup_interface sl_xdg_popup_implementation = {
|
|
sl_xdg_popup_destroy, ForwardRequest<xdg_popup_grab>};
|
|
|
|
static struct sl_host_surface* get_host_surface(
|
|
struct sl_host_xdg_surface* xdg) {
|
|
// For xdg_popup/xdg_toplevel they will point to the
|
|
// originating xdg_surface. The originating surface
|
|
// will point to the source sl_host_surface
|
|
if (xdg && xdg->originator)
|
|
return xdg->originator;
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
static void sl_xdg_popup_configure(void* data,
|
|
struct xdg_popup* xdg_popup,
|
|
int32_t x,
|
|
int32_t y,
|
|
int32_t width,
|
|
int32_t height) {
|
|
struct sl_host_xdg_popup* host =
|
|
static_cast<sl_host_xdg_popup*>(xdg_popup_get_user_data(xdg_popup));
|
|
int32_t x1 = x;
|
|
int32_t y1 = y;
|
|
int32_t x2 = x + width;
|
|
int32_t y2 = y + height;
|
|
|
|
sl_transform_host_to_guest(host->ctx, get_host_surface(host->originator), &x1,
|
|
&y1);
|
|
sl_transform_host_to_guest(host->ctx, get_host_surface(host->originator), &x2,
|
|
&y2);
|
|
|
|
xdg_popup_send_configure(host->resource, x1, y1, x2 - x1, y2 - y1);
|
|
}
|
|
|
|
static void sl_xdg_popup_popup_done(void* data, struct xdg_popup* xdg_popup) {
|
|
struct sl_host_xdg_popup* host =
|
|
static_cast<sl_host_xdg_popup*>(xdg_popup_get_user_data(xdg_popup));
|
|
|
|
xdg_popup_send_popup_done(host->resource);
|
|
}
|
|
|
|
static const struct xdg_popup_listener sl_xdg_popup_listener = {
|
|
sl_xdg_popup_configure, sl_xdg_popup_popup_done};
|
|
|
|
static void sl_destroy_host_xdg_popup(struct wl_resource* resource) {
|
|
struct sl_host_xdg_popup* host =
|
|
static_cast<sl_host_xdg_popup*>(wl_resource_get_user_data(resource));
|
|
|
|
xdg_popup_destroy(host->proxy);
|
|
wl_resource_set_user_data(resource, NULL);
|
|
delete host;
|
|
}
|
|
|
|
static void sl_xdg_toplevel_destroy(struct wl_client* client,
|
|
struct wl_resource* resource) {
|
|
wl_resource_destroy(resource);
|
|
}
|
|
|
|
static void sl_xdg_toplevel_show_window_menu(struct wl_client* client,
|
|
struct wl_resource* resource,
|
|
struct wl_resource* seat_resource,
|
|
uint32_t serial,
|
|
int32_t x,
|
|
int32_t y) {
|
|
struct sl_host_xdg_toplevel* host =
|
|
static_cast<sl_host_xdg_toplevel*>(wl_resource_get_user_data(resource));
|
|
struct sl_host_seat* host_seat =
|
|
seat_resource
|
|
? static_cast<sl_host_seat*>(wl_resource_get_user_data(seat_resource))
|
|
: NULL;
|
|
|
|
// TODO(mrisaacb): There was no scaling performed here in the original code.
|
|
// Figure out why this was.
|
|
xdg_toplevel_show_window_menu(
|
|
host->proxy, host_seat ? host_seat->proxy : NULL, serial, x, y);
|
|
} // NOLINT(whitespace/indent)
|
|
|
|
static const struct xdg_toplevel_interface sl_xdg_toplevel_implementation = {
|
|
sl_xdg_toplevel_destroy,
|
|
ForwardRequest<xdg_toplevel_set_parent, AllowNullResource::kYes>,
|
|
ForwardRequest<xdg_toplevel_set_title>,
|
|
ForwardRequest<xdg_toplevel_set_app_id>,
|
|
sl_xdg_toplevel_show_window_menu,
|
|
ForwardRequest<xdg_toplevel_move, AllowNullResource::kYes>,
|
|
ForwardRequest<xdg_toplevel_resize, AllowNullResource::kYes>,
|
|
ForwardRequest<xdg_toplevel_set_max_size>,
|
|
ForwardRequest<xdg_toplevel_set_min_size>,
|
|
ForwardRequest<xdg_toplevel_set_maximized>,
|
|
ForwardRequest<xdg_toplevel_unset_maximized>,
|
|
ForwardRequest<xdg_toplevel_set_fullscreen, AllowNullResource::kYes>,
|
|
ForwardRequest<xdg_toplevel_unset_fullscreen>,
|
|
ForwardRequest<xdg_toplevel_set_minimized>,
|
|
};
|
|
|
|
static void sl_xdg_toplevel_configure(void* data,
|
|
struct xdg_toplevel* xdg_toplevel,
|
|
int32_t width,
|
|
int32_t height,
|
|
struct wl_array* states) {
|
|
struct sl_host_xdg_toplevel* host = static_cast<sl_host_xdg_toplevel*>(
|
|
xdg_toplevel_get_user_data(xdg_toplevel));
|
|
|
|
int32_t iwidth = width;
|
|
int32_t iheight = height;
|
|
|
|
sl_transform_host_to_guest(host->ctx, get_host_surface(host->originator),
|
|
&iwidth, &iheight);
|
|
|
|
xdg_toplevel_send_configure(host->resource, iwidth, iheight, states);
|
|
}
|
|
|
|
static void sl_xdg_toplevel_close(void* data,
|
|
struct xdg_toplevel* xdg_toplevel) {
|
|
struct sl_host_xdg_toplevel* host = static_cast<sl_host_xdg_toplevel*>(
|
|
xdg_toplevel_get_user_data(xdg_toplevel));
|
|
|
|
xdg_toplevel_send_close(host->resource);
|
|
}
|
|
|
|
static const struct xdg_toplevel_listener sl_xdg_toplevel_listener = {
|
|
sl_xdg_toplevel_configure, sl_xdg_toplevel_close};
|
|
|
|
static void sl_destroy_host_xdg_toplevel(struct wl_resource* resource) {
|
|
struct sl_host_xdg_toplevel* host =
|
|
static_cast<sl_host_xdg_toplevel*>(wl_resource_get_user_data(resource));
|
|
|
|
xdg_toplevel_destroy(host->proxy);
|
|
wl_resource_set_user_data(resource, NULL);
|
|
delete host;
|
|
}
|
|
|
|
static void sl_xdg_surface_destroy(struct wl_client* client,
|
|
struct wl_resource* resource) {
|
|
wl_resource_destroy(resource);
|
|
}
|
|
|
|
static void sl_xdg_surface_get_toplevel(struct wl_client* client,
|
|
struct wl_resource* resource,
|
|
uint32_t id) {
|
|
struct sl_host_xdg_surface* host =
|
|
static_cast<sl_host_xdg_surface*>(wl_resource_get_user_data(resource));
|
|
struct sl_host_xdg_toplevel* host_xdg_toplevel = new sl_host_xdg_toplevel();
|
|
|
|
host_xdg_toplevel->ctx = host->ctx;
|
|
host_xdg_toplevel->resource =
|
|
wl_resource_create(client, &xdg_toplevel_interface, 1, id);
|
|
wl_resource_set_implementation(
|
|
host_xdg_toplevel->resource, &sl_xdg_toplevel_implementation,
|
|
host_xdg_toplevel, sl_destroy_host_xdg_toplevel);
|
|
host_xdg_toplevel->proxy = xdg_surface_get_toplevel(host->proxy);
|
|
host_xdg_toplevel->originator = host;
|
|
|
|
xdg_toplevel_add_listener(host_xdg_toplevel->proxy, &sl_xdg_toplevel_listener,
|
|
host_xdg_toplevel);
|
|
}
|
|
|
|
static void sl_xdg_surface_get_popup(struct wl_client* client,
|
|
struct wl_resource* resource,
|
|
uint32_t id,
|
|
struct wl_resource* parent_resource,
|
|
struct wl_resource* positioner_resource) {
|
|
struct sl_host_xdg_surface* host =
|
|
static_cast<sl_host_xdg_surface*>(wl_resource_get_user_data(resource));
|
|
struct sl_host_xdg_surface* host_parent =
|
|
parent_resource ? static_cast<sl_host_xdg_surface*>(
|
|
wl_resource_get_user_data(parent_resource))
|
|
: NULL;
|
|
struct sl_host_xdg_positioner* host_positioner =
|
|
static_cast<sl_host_xdg_positioner*>(
|
|
wl_resource_get_user_data(positioner_resource));
|
|
struct sl_host_xdg_popup* host_xdg_popup = new sl_host_xdg_popup();
|
|
|
|
host_xdg_popup->ctx = host->ctx;
|
|
host_xdg_popup->resource =
|
|
wl_resource_create(client, &xdg_popup_interface, 1, id);
|
|
wl_resource_set_implementation(host_xdg_popup->resource,
|
|
&sl_xdg_popup_implementation, host_xdg_popup,
|
|
sl_destroy_host_xdg_popup);
|
|
host_xdg_popup->proxy = xdg_surface_get_popup(
|
|
host->proxy, host_parent ? host_parent->proxy : NULL,
|
|
host_positioner->proxy);
|
|
host_xdg_popup->originator = host_parent;
|
|
|
|
xdg_popup_add_listener(host_xdg_popup->proxy, &sl_xdg_popup_listener,
|
|
host_xdg_popup);
|
|
} // NOLINT(whitespace/indent)
|
|
|
|
static void sl_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) {
|
|
struct sl_host_xdg_surface* host =
|
|
static_cast<sl_host_xdg_surface*>(wl_resource_get_user_data(resource));
|
|
int32_t x1 = x;
|
|
int32_t y1 = y;
|
|
int32_t x2 = x + width;
|
|
int32_t y2 = y + height;
|
|
|
|
sl_transform_guest_to_host(host->ctx, host->originator, &x1, &y1);
|
|
sl_transform_guest_to_host(host->ctx, host->originator, &x2, &y2);
|
|
|
|
xdg_surface_set_window_geometry(host->proxy, x1, y1, x2 - x1, y2 - y1);
|
|
}
|
|
|
|
static const struct xdg_surface_interface sl_xdg_surface_implementation = {
|
|
sl_xdg_surface_destroy, sl_xdg_surface_get_toplevel,
|
|
sl_xdg_surface_get_popup, sl_xdg_surface_set_window_geometry,
|
|
ForwardRequest<xdg_surface_ack_configure>};
|
|
|
|
static void sl_xdg_surface_configure(void* data,
|
|
struct xdg_surface* xdg_surface,
|
|
uint32_t serial) {
|
|
struct sl_host_xdg_surface* host =
|
|
static_cast<sl_host_xdg_surface*>(xdg_surface_get_user_data(xdg_surface));
|
|
|
|
xdg_surface_send_configure(host->resource, serial);
|
|
}
|
|
|
|
static const struct xdg_surface_listener sl_xdg_surface_listener = {
|
|
sl_xdg_surface_configure};
|
|
|
|
static void sl_destroy_host_xdg_surface(struct wl_resource* resource) {
|
|
struct sl_host_xdg_surface* host =
|
|
static_cast<sl_host_xdg_surface*>(wl_resource_get_user_data(resource));
|
|
|
|
xdg_surface_destroy(host->proxy);
|
|
wl_resource_set_user_data(resource, NULL);
|
|
delete host;
|
|
}
|
|
|
|
static void sl_xdg_shell_destroy(struct wl_client* client,
|
|
struct wl_resource* resource) {
|
|
wl_resource_destroy(resource);
|
|
}
|
|
|
|
static void sl_xdg_shell_create_positioner(struct wl_client* client,
|
|
struct wl_resource* resource,
|
|
uint32_t id) {
|
|
struct sl_host_xdg_shell* host =
|
|
static_cast<sl_host_xdg_shell*>(wl_resource_get_user_data(resource));
|
|
struct sl_host_xdg_positioner* host_xdg_positioner =
|
|
new sl_host_xdg_positioner();
|
|
|
|
host_xdg_positioner->ctx = host->ctx;
|
|
host_xdg_positioner->resource =
|
|
wl_resource_create(client, &xdg_positioner_interface, 1, id);
|
|
wl_resource_set_implementation(
|
|
host_xdg_positioner->resource, &sl_xdg_positioner_implementation,
|
|
host_xdg_positioner, sl_destroy_host_xdg_positioner);
|
|
host_xdg_positioner->proxy = xdg_wm_base_create_positioner(host->proxy);
|
|
xdg_positioner_set_user_data(host_xdg_positioner->proxy, host_xdg_positioner);
|
|
}
|
|
|
|
static void sl_xdg_shell_get_xdg_surface(struct wl_client* client,
|
|
struct wl_resource* resource,
|
|
uint32_t id,
|
|
struct wl_resource* surface_resource) {
|
|
struct sl_host_xdg_shell* host =
|
|
static_cast<sl_host_xdg_shell*>(wl_resource_get_user_data(resource));
|
|
struct sl_host_surface* host_surface = static_cast<sl_host_surface*>(
|
|
wl_resource_get_user_data(surface_resource));
|
|
struct sl_host_xdg_surface* host_xdg_surface = new sl_host_xdg_surface();
|
|
|
|
host_xdg_surface->ctx = host->ctx;
|
|
host_xdg_surface->resource =
|
|
wl_resource_create(client, &xdg_surface_interface, 1, id);
|
|
wl_resource_set_implementation(host_xdg_surface->resource,
|
|
&sl_xdg_surface_implementation,
|
|
host_xdg_surface, sl_destroy_host_xdg_surface);
|
|
host_xdg_surface->proxy =
|
|
xdg_wm_base_get_xdg_surface(host->proxy, host_surface->proxy);
|
|
host_xdg_surface->originator = host_surface;
|
|
|
|
xdg_surface_add_listener(host_xdg_surface->proxy, &sl_xdg_surface_listener,
|
|
host_xdg_surface);
|
|
host_surface->has_role = 1;
|
|
}
|
|
|
|
static const struct xdg_wm_base_interface sl_xdg_shell_implementation = {
|
|
sl_xdg_shell_destroy, sl_xdg_shell_create_positioner,
|
|
sl_xdg_shell_get_xdg_surface, ForwardRequest<xdg_wm_base_pong>};
|
|
|
|
static void sl_xdg_shell_ping(void* data,
|
|
struct xdg_wm_base* xdg_shell,
|
|
uint32_t serial) {
|
|
struct sl_host_xdg_shell* host =
|
|
static_cast<sl_host_xdg_shell*>(xdg_wm_base_get_user_data(xdg_shell));
|
|
|
|
xdg_wm_base_send_ping(host->resource, serial);
|
|
}
|
|
|
|
static const struct xdg_wm_base_listener sl_xdg_shell_listener = {
|
|
sl_xdg_shell_ping};
|
|
|
|
static void sl_destroy_host_xdg_shell(struct wl_resource* resource) {
|
|
struct sl_host_xdg_shell* host =
|
|
static_cast<sl_host_xdg_shell*>(wl_resource_get_user_data(resource));
|
|
|
|
xdg_wm_base_destroy(host->proxy);
|
|
wl_resource_set_user_data(resource, NULL);
|
|
delete host;
|
|
}
|
|
|
|
static void sl_bind_host_xdg_shell(struct wl_client* client,
|
|
void* data,
|
|
uint32_t version,
|
|
uint32_t id) {
|
|
struct sl_context* ctx = (struct sl_context*)data;
|
|
struct sl_host_xdg_shell* host = new sl_host_xdg_shell();
|
|
host->ctx = ctx;
|
|
host->resource = wl_resource_create(client, &xdg_wm_base_interface, 1, id);
|
|
wl_resource_set_implementation(host->resource, &sl_xdg_shell_implementation,
|
|
host, sl_destroy_host_xdg_shell);
|
|
host->proxy = static_cast<xdg_wm_base*>(
|
|
wl_registry_bind(wl_display_get_registry(ctx->display),
|
|
ctx->xdg_shell->id, &xdg_wm_base_interface, 1));
|
|
xdg_wm_base_add_listener(host->proxy, &sl_xdg_shell_listener, host);
|
|
}
|
|
|
|
struct sl_global* sl_xdg_shell_global_create(struct sl_context* ctx) {
|
|
return sl_global_create(ctx, &xdg_wm_base_interface, 1, ctx,
|
|
sl_bind_host_xdg_shell);
|
|
}
|