blob: 5e205299c0334b4e39ff4c536f9f7099e56b6058 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_X_XPROTO_TYPES_H_
#define UI_GFX_X_XPROTO_TYPES_H_
#include <X11/Xlib-xcb.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
#include <cstdint>
#include <memory>
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/free_deleter.h"
#include "base/optional.h"
#include "ui/gfx/x/xproto_util.h"
typedef struct _XDisplay XDisplay;
namespace x11 {
class Connection;
namespace detail {
template <typename Reply>
std::unique_ptr<Reply> ReadReply(const uint8_t* buffer);
} // namespace detail
using Error = xcb_generic_error_t;
template <class Reply>
class Future;
template <typename T>
T Read(const uint8_t* buf);
template <typename T>
std::vector<uint8_t> Write(const T& t);
template <typename Reply>
struct Response {
operator bool() const { return reply.get(); }
const Reply* operator->() const { return reply.get(); }
std::unique_ptr<Reply> reply;
std::unique_ptr<Error, base::FreeDeleter> error;
private:
friend class Future<Reply>;
Response(std::unique_ptr<Reply> reply,
std::unique_ptr<Error, base::FreeDeleter> error)
: reply(std::move(reply)), error(std::move(error)) {}
};
template <>
struct Response<void> {
std::unique_ptr<Error, base::FreeDeleter> error;
private:
friend class Future<void>;
explicit Response(std::unique_ptr<Error, base::FreeDeleter> error)
: error(std::move(error)) {}
};
class COMPONENT_EXPORT(X11) FutureBase {
public:
using RawReply = std::unique_ptr<uint8_t, base::FreeDeleter>;
using RawError = std::unique_ptr<xcb_generic_error_t, base::FreeDeleter>;
using ResponseCallback =
base::OnceCallback<void(RawReply reply, RawError error)>;
FutureBase(const FutureBase&) = delete;
FutureBase& operator=(const FutureBase&) = delete;
protected:
FutureBase(Connection* connection, base::Optional<unsigned int> sequence);
~FutureBase();
FutureBase(FutureBase&& future);
FutureBase& operator=(FutureBase&& future);
void SyncImpl(Error** raw_error, uint8_t** raw_reply);
void SyncImpl(Error** raw_error);
void OnResponseImpl(ResponseCallback callback);
private:
Connection* connection_;
base::Optional<unsigned int> sequence_;
};
// An x11::Future wraps an asynchronous response from the X11 server. The
// response may be waited-for with Sync(), or asynchronously handled by
// installing a response handler using OnResponse().
template <typename Reply>
class Future : public FutureBase {
public:
using Callback = base::OnceCallback<void(Response<Reply> response)>;
// Blocks until we receive the response from the server. Returns the response.
Response<Reply> Sync() {
Error* raw_error = nullptr;
uint8_t* raw_reply = nullptr;
SyncImpl(&raw_error, &raw_reply);
std::unique_ptr<Reply> reply;
if (raw_reply) {
reply = detail::ReadReply<Reply>(raw_reply);
free(raw_reply);
}
std::unique_ptr<Error, base::FreeDeleter> error;
if (raw_error)
error.reset(raw_error);
return {std::move(reply), std::move(error)};
}
// Installs |callback| to be run when the response is received.
void OnResponse(Callback callback) {
// This intermediate callback handles the conversion from |raw_reply| to a
// real Reply object before feeding the result to |callback|. This means
// |callback| must be bound as the first argument of the intermediate
// function.
auto wrapper = [](Callback callback, RawReply raw_reply, RawError error) {
std::unique_ptr<Reply> reply =
raw_reply ? detail::ReadReply<Reply>(raw_reply.get()) : nullptr;
std::move(callback).Run({std::move(reply), std::move(error)});
};
OnResponseImpl(base::BindOnce(wrapper, std::move(callback)));
}
private:
template <typename R>
friend Future<R> SendRequest(Connection*, std::vector<uint8_t>*);
Future(Connection* connection, base::Optional<unsigned int> sequence)
: FutureBase(connection, sequence) {}
};
// Sync() specialization for requests that don't generate replies. The returned
// response will only contain an error if there was one.
template <>
inline Response<void> Future<void>::Sync() {
Error* raw_error = nullptr;
SyncImpl(&raw_error);
std::unique_ptr<Error, base::FreeDeleter> error;
if (raw_error)
error.reset(raw_error);
return Response<void>{std::move(error)};
}
// OnResponse() specialization for requests that don't generate replies. The
// response argument to |callback| will only contain an error if there was one.
template <>
inline void Future<void>::OnResponse(Callback callback) {
// See Future<Reply>::OnResponse() for an explanation of why
// this wrapper is necessary.
auto wrapper = [](Callback callback, RawReply reply, RawError error) {
DCHECK(!reply);
std::move(callback).Run(Response<void>{std::move(error)});
};
OnResponseImpl(base::BindOnce(wrapper, std::move(callback)));
}
} // namespace x11
#endif // UI_GFX_X_XPROTO_TYPES_H_