blob: 2be7ef43ec471bc94c7646a94ed559feac0c7278 [file] [log] [blame] [edit]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef VM_TOOLS_SOMMELIER_SOMMELIER_UTIL_H_
#define VM_TOOLS_SOMMELIER_SOMMELIER_UTIL_H_
#include <assert.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <memory>
#include <wayland-client-protocol.h>
#include <wayland-server.h>
#define errno_assert(rv) \
{ \
int macro_private_assert_value = (rv); \
if (!macro_private_assert_value) { \
fprintf(stderr, "Unexpected error: %s\n", strerror(errno)); \
assert(false); \
} \
}
#define UNUSED(x) ((void)(x))
// Performs an asprintf operation and checks the result for validity and calls
// abort() if there's a failure. Returns a newly allocated string rather than
// taking a double pointer argument like asprintf.
__attribute__((__format__(__printf__, 1, 0))) char* sl_xasprintf(
const char* fmt, ...);
#define DEFAULT_DELETER_FDECL(TypeName) \
namespace std { \
template <> \
struct default_delete<TypeName> { \
void operator()(TypeName* ptr); \
}; \
}
DEFAULT_DELETER_FDECL(struct wl_event_source);
// Maps wl_ to sl_ types, e.g. WlToSl<wl_seat>::type == sl_host_seat.
template <typename WaylandType>
struct WlToSl;
#define MAP_STRUCTS(WlType, SlType) \
template <> \
struct WlToSl<WlType> { \
using type = SlType; \
};
// Convert a request argument of type InArg to type OutArg. InArg is the type
// sommelier receives as a Wayland host. OutArg is the type used passed to the
// real host compositor. For Wayland resources, these will be wl_resource* and
// wl_..* (e.g. wl_surface*) respectively.
template <typename InArg, typename OutArg>
struct ConvertRequestArg {};
template <>
struct ConvertRequestArg<const char*, const char*> {
inline static const char* Convert(const char* arg) { return arg; }
};
template <>
struct ConvertRequestArg<uint32_t, uint32_t> {
inline static uint32_t Convert(uint32_t arg) { return arg; }
};
template <>
struct ConvertRequestArg<int32_t, int32_t> {
inline static int32_t Convert(int32_t arg) { return arg; }
};
template <typename OutArg>
struct ConvertRequestArg<wl_resource*, OutArg*> {
static OutArg* Convert(wl_resource* resource) {
if (!resource) {
return nullptr;
}
using SlType = typename WlToSl<OutArg>::type;
SlType* host = static_cast<SlType*>(wl_resource_get_user_data(resource));
return host ? host->proxy : nullptr;
}
};
template <typename T>
inline bool IsNullWlResource(T arg) {
return false;
}
template <>
inline bool IsNullWlResource(wl_resource* resource) {
return resource == nullptr;
}
enum class AllowNullResource {
kNo = 0,
kYes = 1,
};
// Invoke the given wl_ function with each arg converted. This helper struct is
// so we can extract types from the wl_ function into a parameter pack for the
// fold expression and not require them to be explicitly written out.
template <typename... T>
struct ForwardRequestHelper;
template <typename... OutArgs>
struct ForwardRequestHelper<void (*)(OutArgs...)> {
template <auto wl_function, AllowNullResource allow_null, typename... InArgs>
static void Forward(struct wl_client* client, InArgs... args) {
if (allow_null == AllowNullResource::kNo) {
if ((IsNullWlResource<InArgs>(args) || ...)) {
fprintf(stderr, "error: received unexpected null resource in: %s\n",
__PRETTY_FUNCTION__);
return;
}
}
wl_function(ConvertRequestArg<InArgs, OutArgs>::Convert(args)...);
}
};
// Similar to the above template, however, it takes an extra class type so we
// can access member functions.
template <typename C, typename... OutArgs>
struct ForwardRequestHelper<void (C::*)(OutArgs...)> {
template <auto shim_getter,
auto function,
AllowNullResource allow_null,
typename... InArgs>
static void Forward(struct wl_client* client, InArgs... args) {
if (allow_null == AllowNullResource::kNo) {
if ((IsNullWlResource<InArgs>(args) || ...)) {
fprintf(stderr, "error: received unexpected null resource in: %s\n",
__PRETTY_FUNCTION__);
return;
}
}
(shim_getter()->*function)(
ConvertRequestArg<InArgs, OutArgs>::Convert(args)...);
}
};
// Wraps a function which forwards a request from a client which is connected to
// Sommelier to the server Sommelier is connected to.
//
// If null Wayland resources should be allowed, AllowNullResource::kYes should
// be set, otherwise the request will be considered invalid and dropped.
// Example usage:
// - ForwardRequest<wl_shell_surface_move>,
// - ForwardRequest<wl_shell_surface_set_fullscreen, AllowNullResource::kYes>
//
// The first argument (receiving object) is guaranteed by Wayland to be
// non-null but for code simplicity it is handled the same as the request
// arguments, with null being allowed or disallowed based on |allow_null|.
template <auto wl_function,
AllowNullResource allow_null = AllowNullResource::kNo,
typename... InArgs>
void ForwardRequest(InArgs... args) {
ForwardRequestHelper<decltype(wl_function)>::template Forward<wl_function,
allow_null>(
args...);
}
// Same as the above function, but it wraps around the shim functions that are
// generated via gen-shim.py.
// Usage:
// - ForwardRequestShim<xdg_positioner_shim, set_anchor>
// - ForwardRequestShim<xdg_positioner_shim, set_anchor,
// AllowNullResource::kYes>
template <auto shim_getter,
auto function,
AllowNullResource allow_null = AllowNullResource::kNo,
typename... InArgs>
void ForwardRequestToShim(InArgs... args) {
ForwardRequestHelper<decltype(function)>::template Forward<
shim_getter, function, allow_null>(args...);
}
// Wraps a function which forwards an event from a server which Sommelier is
// connected to to a client which is connected to Sommelier.
//
// Example usage:
// - ForwardEvent<wl_shell_surface_send_ping>
template <auto wl_function, typename T, typename... InArgs>
void ForwardEvent(void* data, T* resource, InArgs... args) {
using SlType = typename WlToSl<T>::type;
SlType* host = static_cast<SlType*>(
wl_proxy_get_user_data(reinterpret_cast<struct wl_proxy*>(resource)));
wl_function(host->resource, args...);
}
// Utility templated function to help readability of unimplemented/ignored
// implementations of listener/implementation functions.
// Example usage:
// static const struct zaura_output_listener sl_aura_output_listener = {
// DoNothing, DoNothing, DoNothing,
// DoNothing, DoNothing
// }
template <typename... InArgs>
void DoNothing(InArgs... ignored) {}
#endif // VM_TOOLS_SOMMELIER_SOMMELIER_UTIL_H_