#include "randr.h"

#include <xcb/xcb.h>
#include <xcb/xcbext.h>

#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "ui/gfx/x/xproto_internal.h"

namespace x11 {

RandR::RandR(x11::Connection* connection,
    const x11::QueryExtensionReply& info)
    : connection_(connection), info_(info) {}

template <> COMPONENT_EXPORT(X11)
void ReadEvent<RandR::ScreenChangeNotifyEvent>(
    RandR::ScreenChangeNotifyEvent* event_, ReadBuffer* buffer) {
  auto& buf = *buffer;

  auto& rotation = (*event_).rotation;
  auto& sequence = (*event_).sequence;
  auto& timestamp = (*event_).timestamp;
  auto& config_timestamp = (*event_).config_timestamp;
  auto& root = (*event_).root;
  auto& request_window = (*event_).request_window;
  auto& sizeID = (*event_).sizeID;
  auto& subpixel_order = (*event_).subpixel_order;
  auto& width = (*event_).width;
  auto& height = (*event_).height;
  auto& mwidth = (*event_).mwidth;
  auto& mheight = (*event_).mheight;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // rotation
  uint8_t tmp0;
  Read(&tmp0, &buf);
  rotation = static_cast<RandR::Rotation>(tmp0);

  // sequence
  Read(&sequence, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // config_timestamp
  Read(&config_timestamp, &buf);

  // root
  Read(&root, &buf);

  // request_window
  Read(&request_window, &buf);

  // sizeID
  Read(&sizeID, &buf);

  // subpixel_order
  uint16_t tmp1;
  Read(&tmp1, &buf);
  subpixel_order = static_cast<Render::SubPixel>(tmp1);

  // width
  Read(&width, &buf);

  // height
  Read(&height, &buf);

  // mwidth
  Read(&mwidth, &buf);

  // mheight
  Read(&mheight, &buf);

  DCHECK_LE(buf.offset, 32ul);
}

template <> COMPONENT_EXPORT(X11)
void ReadEvent<RandR::NotifyEvent>(
    RandR::NotifyEvent* event_, ReadBuffer* buffer) {
  auto& buf = *buffer;

  RandR::Notify subCode{};
  auto& sequence = (*event_).sequence;
  auto& data = (*event_);

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // subCode
  uint8_t tmp2;
  Read(&tmp2, &buf);
  subCode = static_cast<RandR::Notify>(tmp2);

  // sequence
  Read(&sequence, &buf);

  // data
  auto data_expr = subCode;
  if (CaseEq(data_expr, RandR::Notify::CrtcChange)) {
    data.cc.emplace();
    auto& timestamp = (*data.cc).timestamp;
    auto& window = (*data.cc).window;
    auto& crtc = (*data.cc).crtc;
    auto& mode = (*data.cc).mode;
    auto& rotation = (*data.cc).rotation;
    auto& x = (*data.cc).x;
    auto& y = (*data.cc).y;
    auto& width = (*data.cc).width;
    auto& height = (*data.cc).height;

    // timestamp
    Read(&timestamp, &buf);

    // window
    Read(&window, &buf);

    // crtc
    Read(&crtc, &buf);

    // mode
    Read(&mode, &buf);

    // rotation
    uint16_t tmp3;
    Read(&tmp3, &buf);
    rotation = static_cast<RandR::Rotation>(tmp3);

    // pad0
    Pad(&buf, 2);

    // x
    Read(&x, &buf);

    // y
    Read(&y, &buf);

    // width
    Read(&width, &buf);

    // height
    Read(&height, &buf);

  }
  if (CaseEq(data_expr, RandR::Notify::OutputChange)) {
    data.oc.emplace();
    auto& timestamp = (*data.oc).timestamp;
    auto& config_timestamp = (*data.oc).config_timestamp;
    auto& window = (*data.oc).window;
    auto& output = (*data.oc).output;
    auto& crtc = (*data.oc).crtc;
    auto& mode = (*data.oc).mode;
    auto& rotation = (*data.oc).rotation;
    auto& connection = (*data.oc).connection;
    auto& subpixel_order = (*data.oc).subpixel_order;

    // timestamp
    Read(&timestamp, &buf);

    // config_timestamp
    Read(&config_timestamp, &buf);

    // window
    Read(&window, &buf);

    // output
    Read(&output, &buf);

    // crtc
    Read(&crtc, &buf);

    // mode
    Read(&mode, &buf);

    // rotation
    uint16_t tmp4;
    Read(&tmp4, &buf);
    rotation = static_cast<RandR::Rotation>(tmp4);

    // connection
    uint8_t tmp5;
    Read(&tmp5, &buf);
    connection = static_cast<RandR::RandRConnection>(tmp5);

    // subpixel_order
    uint8_t tmp6;
    Read(&tmp6, &buf);
    subpixel_order = static_cast<Render::SubPixel>(tmp6);

  }
  if (CaseEq(data_expr, RandR::Notify::OutputProperty)) {
    data.op.emplace();
    auto& window = (*data.op).window;
    auto& output = (*data.op).output;
    auto& atom = (*data.op).atom;
    auto& timestamp = (*data.op).timestamp;
    auto& status = (*data.op).status;

    // window
    Read(&window, &buf);

    // output
    Read(&output, &buf);

    // atom
    Read(&atom, &buf);

    // timestamp
    Read(&timestamp, &buf);

    // status
    uint8_t tmp7;
    Read(&tmp7, &buf);
    status = static_cast<Property>(tmp7);

    // pad1
    Pad(&buf, 11);

  }
  if (CaseEq(data_expr, RandR::Notify::ProviderChange)) {
    data.pc.emplace();
    auto& timestamp = (*data.pc).timestamp;
    auto& window = (*data.pc).window;
    auto& provider = (*data.pc).provider;

    // timestamp
    Read(&timestamp, &buf);

    // window
    Read(&window, &buf);

    // provider
    Read(&provider, &buf);

    // pad2
    Pad(&buf, 16);

  }
  if (CaseEq(data_expr, RandR::Notify::ProviderProperty)) {
    data.pp.emplace();
    auto& window = (*data.pp).window;
    auto& provider = (*data.pp).provider;
    auto& atom = (*data.pp).atom;
    auto& timestamp = (*data.pp).timestamp;
    auto& state = (*data.pp).state;

    // window
    Read(&window, &buf);

    // provider
    Read(&provider, &buf);

    // atom
    Read(&atom, &buf);

    // timestamp
    Read(&timestamp, &buf);

    // state
    Read(&state, &buf);

    // pad3
    Pad(&buf, 11);

  }
  if (CaseEq(data_expr, RandR::Notify::ResourceChange)) {
    data.rc.emplace();
    auto& timestamp = (*data.rc).timestamp;
    auto& window = (*data.rc).window;

    // timestamp
    Read(&timestamp, &buf);

    // window
    Read(&window, &buf);

    // pad4
    Pad(&buf, 20);

  }
  if (CaseEq(data_expr, RandR::Notify::Lease)) {
    data.lc.emplace();
    auto& timestamp = (*data.lc).timestamp;
    auto& window = (*data.lc).window;
    auto& lease = (*data.lc).lease;
    auto& created = (*data.lc).created;

    // timestamp
    Read(&timestamp, &buf);

    // window
    Read(&window, &buf);

    // lease
    Read(&lease, &buf);

    // created
    Read(&created, &buf);

    // pad5
    Pad(&buf, 15);

  }

  DCHECK_LE(buf.offset, 32ul);
}

Future<RandR::QueryVersionReply>
RandR::QueryVersion(
    const RandR::QueryVersionRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& major_version = request.major_version;
  auto& minor_version = request.minor_version;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 0;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // major_version
  buf.Write(&major_version);

  // minor_version
  buf.Write(&minor_version);

  Align(&buf, 4);

  return x11::SendRequest<RandR::QueryVersionReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::QueryVersionReply>
ReadReply<RandR::QueryVersionReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::QueryVersionReply>();

  auto& sequence = (*reply).sequence;
  auto& major_version = (*reply).major_version;
  auto& minor_version = (*reply).minor_version;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // major_version
  Read(&major_version, &buf);

  // minor_version
  Read(&minor_version, &buf);

  // pad1
  Pad(&buf, 16);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::SetScreenConfigReply>
RandR::SetScreenConfig(
    const RandR::SetScreenConfigRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;
  auto& timestamp = request.timestamp;
  auto& config_timestamp = request.config_timestamp;
  auto& sizeID = request.sizeID;
  auto& rotation = request.rotation;
  auto& rate = request.rate;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 2;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  // timestamp
  buf.Write(&timestamp);

  // config_timestamp
  buf.Write(&config_timestamp);

  // sizeID
  buf.Write(&sizeID);

  // rotation
  uint16_t tmp8;
  tmp8 = static_cast<uint16_t>(rotation);
  buf.Write(&tmp8);

  // rate
  buf.Write(&rate);

  // pad0
  Pad(&buf, 2);

  Align(&buf, 4);

  return x11::SendRequest<RandR::SetScreenConfigReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::SetScreenConfigReply>
ReadReply<RandR::SetScreenConfigReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::SetScreenConfigReply>();

  auto& status = (*reply).status;
  auto& sequence = (*reply).sequence;
  auto& new_timestamp = (*reply).new_timestamp;
  auto& config_timestamp = (*reply).config_timestamp;
  auto& root = (*reply).root;
  auto& subpixel_order = (*reply).subpixel_order;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // status
  uint8_t tmp9;
  Read(&tmp9, &buf);
  status = static_cast<x11::RandR::SetConfig>(tmp9);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // new_timestamp
  Read(&new_timestamp, &buf);

  // config_timestamp
  Read(&config_timestamp, &buf);

  // root
  Read(&root, &buf);

  // subpixel_order
  uint16_t tmp10;
  Read(&tmp10, &buf);
  subpixel_order = static_cast<x11::Render::SubPixel>(tmp10);

  // pad0
  Pad(&buf, 10);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::SelectInput(
    const RandR::SelectInputRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;
  auto& enable = request.enable;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 4;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  // enable
  uint16_t tmp11;
  tmp11 = static_cast<uint16_t>(enable);
  buf.Write(&tmp11);

  // pad0
  Pad(&buf, 2);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::GetScreenInfoReply>
RandR::GetScreenInfo(
    const RandR::GetScreenInfoRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 5;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetScreenInfoReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetScreenInfoReply>
ReadReply<RandR::GetScreenInfoReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetScreenInfoReply>();

  auto& rotations = (*reply).rotations;
  auto& sequence = (*reply).sequence;
  auto& root = (*reply).root;
  auto& timestamp = (*reply).timestamp;
  auto& config_timestamp = (*reply).config_timestamp;
  uint16_t nSizes{};
  auto& sizeID = (*reply).sizeID;
  auto& rotation = (*reply).rotation;
  auto& rate = (*reply).rate;
  auto& nInfo = (*reply).nInfo;
  auto& sizes = (*reply).sizes;
  size_t sizes_len = sizes.size();
  auto& rates = (*reply).rates;
  size_t rates_len = rates.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // rotations
  uint8_t tmp12;
  Read(&tmp12, &buf);
  rotations = static_cast<x11::RandR::Rotation>(tmp12);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // root
  Read(&root, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // config_timestamp
  Read(&config_timestamp, &buf);

  // nSizes
  Read(&nSizes, &buf);

  // sizeID
  Read(&sizeID, &buf);

  // rotation
  uint16_t tmp13;
  Read(&tmp13, &buf);
  rotation = static_cast<x11::RandR::Rotation>(tmp13);

  // rate
  Read(&rate, &buf);

  // nInfo
  Read(&nInfo, &buf);

  // pad0
  Pad(&buf, 2);

  // sizes
  sizes.resize(nSizes);
  for (auto& sizes_elem : sizes) {
    // sizes_elem
    {
      auto& width = sizes_elem.width;
      auto& height = sizes_elem.height;
      auto& mwidth = sizes_elem.mwidth;
      auto& mheight = sizes_elem.mheight;

      // width
      Read(&width, &buf);

      // height
      Read(&height, &buf);

      // mwidth
      Read(&mwidth, &buf);

      // mheight
      Read(&mheight, &buf);

    }

  }

  // rates
  rates.resize((nInfo) - (nSizes));
  for (auto& rates_elem : rates) {
    // rates_elem
    {
      uint16_t nRates{};
      auto& rates = rates_elem.rates;
      size_t rates_len = rates.size();

      // nRates
      Read(&nRates, &buf);

      // rates
      rates.resize(nRates);
      for (auto& rates_elem : rates) {
        // rates_elem
        Read(&rates_elem, &buf);

      }

    }

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::GetScreenSizeRangeReply>
RandR::GetScreenSizeRange(
    const RandR::GetScreenSizeRangeRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 6;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetScreenSizeRangeReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetScreenSizeRangeReply>
ReadReply<RandR::GetScreenSizeRangeReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetScreenSizeRangeReply>();

  auto& sequence = (*reply).sequence;
  auto& min_width = (*reply).min_width;
  auto& min_height = (*reply).min_height;
  auto& max_width = (*reply).max_width;
  auto& max_height = (*reply).max_height;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // min_width
  Read(&min_width, &buf);

  // min_height
  Read(&min_height, &buf);

  // max_width
  Read(&max_width, &buf);

  // max_height
  Read(&max_height, &buf);

  // pad1
  Pad(&buf, 16);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::SetScreenSize(
    const RandR::SetScreenSizeRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;
  auto& width = request.width;
  auto& height = request.height;
  auto& mm_width = request.mm_width;
  auto& mm_height = request.mm_height;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 7;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  // width
  buf.Write(&width);

  // height
  buf.Write(&height);

  // mm_width
  buf.Write(&mm_width);

  // mm_height
  buf.Write(&mm_height);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::GetScreenResourcesReply>
RandR::GetScreenResources(
    const RandR::GetScreenResourcesRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 8;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetScreenResourcesReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetScreenResourcesReply>
ReadReply<RandR::GetScreenResourcesReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetScreenResourcesReply>();

  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;
  auto& config_timestamp = (*reply).config_timestamp;
  uint16_t num_crtcs{};
  uint16_t num_outputs{};
  uint16_t num_modes{};
  uint16_t names_len{};
  auto& crtcs = (*reply).crtcs;
  size_t crtcs_len = crtcs.size();
  auto& outputs = (*reply).outputs;
  size_t outputs_len = outputs.size();
  auto& modes = (*reply).modes;
  size_t modes_len = modes.size();
  auto& names = (*reply).names;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // config_timestamp
  Read(&config_timestamp, &buf);

  // num_crtcs
  Read(&num_crtcs, &buf);

  // num_outputs
  Read(&num_outputs, &buf);

  // num_modes
  Read(&num_modes, &buf);

  // names_len
  Read(&names_len, &buf);

  // pad1
  Pad(&buf, 8);

  // crtcs
  crtcs.resize(num_crtcs);
  for (auto& crtcs_elem : crtcs) {
    // crtcs_elem
    Read(&crtcs_elem, &buf);

  }

  // outputs
  outputs.resize(num_outputs);
  for (auto& outputs_elem : outputs) {
    // outputs_elem
    Read(&outputs_elem, &buf);

  }

  // modes
  modes.resize(num_modes);
  for (auto& modes_elem : modes) {
    // modes_elem
    {
      auto& id = modes_elem.id;
      auto& width = modes_elem.width;
      auto& height = modes_elem.height;
      auto& dot_clock = modes_elem.dot_clock;
      auto& hsync_start = modes_elem.hsync_start;
      auto& hsync_end = modes_elem.hsync_end;
      auto& htotal = modes_elem.htotal;
      auto& hskew = modes_elem.hskew;
      auto& vsync_start = modes_elem.vsync_start;
      auto& vsync_end = modes_elem.vsync_end;
      auto& vtotal = modes_elem.vtotal;
      auto& name_len = modes_elem.name_len;
      auto& mode_flags = modes_elem.mode_flags;

      // id
      Read(&id, &buf);

      // width
      Read(&width, &buf);

      // height
      Read(&height, &buf);

      // dot_clock
      Read(&dot_clock, &buf);

      // hsync_start
      Read(&hsync_start, &buf);

      // hsync_end
      Read(&hsync_end, &buf);

      // htotal
      Read(&htotal, &buf);

      // hskew
      Read(&hskew, &buf);

      // vsync_start
      Read(&vsync_start, &buf);

      // vsync_end
      Read(&vsync_end, &buf);

      // vtotal
      Read(&vtotal, &buf);

      // name_len
      Read(&name_len, &buf);

      // mode_flags
      uint32_t tmp14;
      Read(&tmp14, &buf);
      mode_flags = static_cast<x11::RandR::ModeFlag>(tmp14);

    }

  }

  // names
  names.resize(names_len);
  for (auto& names_elem : names) {
    // names_elem
    Read(&names_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::GetOutputInfoReply>
RandR::GetOutputInfo(
    const RandR::GetOutputInfoRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& output = request.output;
  auto& config_timestamp = request.config_timestamp;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 9;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // output
  buf.Write(&output);

  // config_timestamp
  buf.Write(&config_timestamp);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetOutputInfoReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetOutputInfoReply>
ReadReply<RandR::GetOutputInfoReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetOutputInfoReply>();

  auto& status = (*reply).status;
  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;
  auto& crtc = (*reply).crtc;
  auto& mm_width = (*reply).mm_width;
  auto& mm_height = (*reply).mm_height;
  auto& connection = (*reply).connection;
  auto& subpixel_order = (*reply).subpixel_order;
  uint16_t num_crtcs{};
  uint16_t num_modes{};
  auto& num_preferred = (*reply).num_preferred;
  uint16_t num_clones{};
  uint16_t name_len{};
  auto& crtcs = (*reply).crtcs;
  size_t crtcs_len = crtcs.size();
  auto& modes = (*reply).modes;
  size_t modes_len = modes.size();
  auto& clones = (*reply).clones;
  size_t clones_len = clones.size();
  auto& name = (*reply).name;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // status
  uint8_t tmp15;
  Read(&tmp15, &buf);
  status = static_cast<x11::RandR::SetConfig>(tmp15);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // crtc
  Read(&crtc, &buf);

  // mm_width
  Read(&mm_width, &buf);

  // mm_height
  Read(&mm_height, &buf);

  // connection
  uint8_t tmp16;
  Read(&tmp16, &buf);
  connection = static_cast<x11::RandR::RandRConnection>(tmp16);

  // subpixel_order
  uint8_t tmp17;
  Read(&tmp17, &buf);
  subpixel_order = static_cast<x11::Render::SubPixel>(tmp17);

  // num_crtcs
  Read(&num_crtcs, &buf);

  // num_modes
  Read(&num_modes, &buf);

  // num_preferred
  Read(&num_preferred, &buf);

  // num_clones
  Read(&num_clones, &buf);

  // name_len
  Read(&name_len, &buf);

  // crtcs
  crtcs.resize(num_crtcs);
  for (auto& crtcs_elem : crtcs) {
    // crtcs_elem
    Read(&crtcs_elem, &buf);

  }

  // modes
  modes.resize(num_modes);
  for (auto& modes_elem : modes) {
    // modes_elem
    Read(&modes_elem, &buf);

  }

  // clones
  clones.resize(num_clones);
  for (auto& clones_elem : clones) {
    // clones_elem
    Read(&clones_elem, &buf);

  }

  // name
  name.resize(name_len);
  for (auto& name_elem : name) {
    // name_elem
    Read(&name_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::ListOutputPropertiesReply>
RandR::ListOutputProperties(
    const RandR::ListOutputPropertiesRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& output = request.output;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 10;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // output
  buf.Write(&output);

  Align(&buf, 4);

  return x11::SendRequest<RandR::ListOutputPropertiesReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::ListOutputPropertiesReply>
ReadReply<RandR::ListOutputPropertiesReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::ListOutputPropertiesReply>();

  auto& sequence = (*reply).sequence;
  uint16_t num_atoms{};
  auto& atoms = (*reply).atoms;
  size_t atoms_len = atoms.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // num_atoms
  Read(&num_atoms, &buf);

  // pad1
  Pad(&buf, 22);

  // atoms
  atoms.resize(num_atoms);
  for (auto& atoms_elem : atoms) {
    // atoms_elem
    Read(&atoms_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::QueryOutputPropertyReply>
RandR::QueryOutputProperty(
    const RandR::QueryOutputPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& output = request.output;
  auto& property = request.property;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 11;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // output
  buf.Write(&output);

  // property
  buf.Write(&property);

  Align(&buf, 4);

  return x11::SendRequest<RandR::QueryOutputPropertyReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::QueryOutputPropertyReply>
ReadReply<RandR::QueryOutputPropertyReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::QueryOutputPropertyReply>();

  auto& sequence = (*reply).sequence;
  auto& pending = (*reply).pending;
  auto& range = (*reply).range;
  auto& immutable = (*reply).immutable;
  auto& validValues = (*reply).validValues;
  size_t validValues_len = validValues.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // pending
  Read(&pending, &buf);

  // range
  Read(&range, &buf);

  // immutable
  Read(&immutable, &buf);

  // pad1
  Pad(&buf, 21);

  // validValues
  validValues.resize(length);
  for (auto& validValues_elem : validValues) {
    // validValues_elem
    Read(&validValues_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::ConfigureOutputProperty(
    const RandR::ConfigureOutputPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& output = request.output;
  auto& property = request.property;
  auto& pending = request.pending;
  auto& range = request.range;
  auto& values = request.values;
  size_t values_len = values.size();

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 12;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // output
  buf.Write(&output);

  // property
  buf.Write(&property);

  // pending
  buf.Write(&pending);

  // range
  buf.Write(&range);

  // pad0
  Pad(&buf, 2);

  // values
  DCHECK_EQ(static_cast<size_t>(values_len), values.size());
  for (auto& values_elem : values) {
    // values_elem
    buf.Write(&values_elem);

  }

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<void>
RandR::ChangeOutputProperty(
    const RandR::ChangeOutputPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& output = request.output;
  auto& property = request.property;
  auto& type = request.type;
  auto& format = request.format;
  auto& mode = request.mode;
  auto& num_units = request.num_units;
  auto& data = request.data;
  size_t data_len = data ? data->size() : 0;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 13;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // output
  buf.Write(&output);

  // property
  buf.Write(&property);

  // type
  buf.Write(&type);

  // format
  buf.Write(&format);

  // mode
  uint8_t tmp18;
  tmp18 = static_cast<uint8_t>(mode);
  buf.Write(&tmp18);

  // pad0
  Pad(&buf, 2);

  // num_units
  buf.Write(&num_units);

  // data
  buf.AppendBuffer(data, ((num_units) * (format)) / (8));

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<void>
RandR::DeleteOutputProperty(
    const RandR::DeleteOutputPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& output = request.output;
  auto& property = request.property;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 14;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // output
  buf.Write(&output);

  // property
  buf.Write(&property);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::GetOutputPropertyReply>
RandR::GetOutputProperty(
    const RandR::GetOutputPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& output = request.output;
  auto& property = request.property;
  auto& type = request.type;
  auto& long_offset = request.long_offset;
  auto& long_length = request.long_length;
  auto& c_delete = request.c_delete;
  auto& pending = request.pending;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 15;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // output
  buf.Write(&output);

  // property
  buf.Write(&property);

  // type
  buf.Write(&type);

  // long_offset
  buf.Write(&long_offset);

  // long_length
  buf.Write(&long_length);

  // c_delete
  buf.Write(&c_delete);

  // pending
  buf.Write(&pending);

  // pad0
  Pad(&buf, 2);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetOutputPropertyReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetOutputPropertyReply>
ReadReply<RandR::GetOutputPropertyReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetOutputPropertyReply>();

  auto& format = (*reply).format;
  auto& sequence = (*reply).sequence;
  auto& type = (*reply).type;
  auto& bytes_after = (*reply).bytes_after;
  auto& num_items = (*reply).num_items;
  auto& data = (*reply).data;
  size_t data_len = data.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // format
  Read(&format, &buf);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // type
  Read(&type, &buf);

  // bytes_after
  Read(&bytes_after, &buf);

  // num_items
  Read(&num_items, &buf);

  // pad0
  Pad(&buf, 12);

  // data
  data.resize((num_items) * ((format) / (8)));
  for (auto& data_elem : data) {
    // data_elem
    Read(&data_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::CreateModeReply>
RandR::CreateMode(
    const RandR::CreateModeRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;
  auto& mode_info = request.mode_info;
  auto& name = request.name;
  size_t name_len = name.size();

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 16;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  // mode_info
  {
    auto& id = mode_info.id;
    auto& width = mode_info.width;
    auto& height = mode_info.height;
    auto& dot_clock = mode_info.dot_clock;
    auto& hsync_start = mode_info.hsync_start;
    auto& hsync_end = mode_info.hsync_end;
    auto& htotal = mode_info.htotal;
    auto& hskew = mode_info.hskew;
    auto& vsync_start = mode_info.vsync_start;
    auto& vsync_end = mode_info.vsync_end;
    auto& vtotal = mode_info.vtotal;
    auto& name_len = mode_info.name_len;
    auto& mode_flags = mode_info.mode_flags;

    // id
    buf.Write(&id);

    // width
    buf.Write(&width);

    // height
    buf.Write(&height);

    // dot_clock
    buf.Write(&dot_clock);

    // hsync_start
    buf.Write(&hsync_start);

    // hsync_end
    buf.Write(&hsync_end);

    // htotal
    buf.Write(&htotal);

    // hskew
    buf.Write(&hskew);

    // vsync_start
    buf.Write(&vsync_start);

    // vsync_end
    buf.Write(&vsync_end);

    // vtotal
    buf.Write(&vtotal);

    // name_len
    buf.Write(&name_len);

    // mode_flags
    uint32_t tmp19;
    tmp19 = static_cast<uint32_t>(mode_flags);
    buf.Write(&tmp19);

  }

  // name
  DCHECK_EQ(static_cast<size_t>(name_len), name.size());
  for (auto& name_elem : name) {
    // name_elem
    buf.Write(&name_elem);

  }

  Align(&buf, 4);

  return x11::SendRequest<RandR::CreateModeReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::CreateModeReply>
ReadReply<RandR::CreateModeReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::CreateModeReply>();

  auto& sequence = (*reply).sequence;
  auto& mode = (*reply).mode;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // mode
  Read(&mode, &buf);

  // pad1
  Pad(&buf, 20);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::DestroyMode(
    const RandR::DestroyModeRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& mode = request.mode;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 17;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // mode
  buf.Write(&mode);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<void>
RandR::AddOutputMode(
    const RandR::AddOutputModeRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& output = request.output;
  auto& mode = request.mode;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 18;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // output
  buf.Write(&output);

  // mode
  buf.Write(&mode);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<void>
RandR::DeleteOutputMode(
    const RandR::DeleteOutputModeRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& output = request.output;
  auto& mode = request.mode;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 19;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // output
  buf.Write(&output);

  // mode
  buf.Write(&mode);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::GetCrtcInfoReply>
RandR::GetCrtcInfo(
    const RandR::GetCrtcInfoRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& crtc = request.crtc;
  auto& config_timestamp = request.config_timestamp;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 20;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // crtc
  buf.Write(&crtc);

  // config_timestamp
  buf.Write(&config_timestamp);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetCrtcInfoReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetCrtcInfoReply>
ReadReply<RandR::GetCrtcInfoReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetCrtcInfoReply>();

  auto& status = (*reply).status;
  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;
  auto& x = (*reply).x;
  auto& y = (*reply).y;
  auto& width = (*reply).width;
  auto& height = (*reply).height;
  auto& mode = (*reply).mode;
  auto& rotation = (*reply).rotation;
  auto& rotations = (*reply).rotations;
  uint16_t num_outputs{};
  uint16_t num_possible_outputs{};
  auto& outputs = (*reply).outputs;
  size_t outputs_len = outputs.size();
  auto& possible = (*reply).possible;
  size_t possible_len = possible.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // status
  uint8_t tmp20;
  Read(&tmp20, &buf);
  status = static_cast<x11::RandR::SetConfig>(tmp20);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // x
  Read(&x, &buf);

  // y
  Read(&y, &buf);

  // width
  Read(&width, &buf);

  // height
  Read(&height, &buf);

  // mode
  Read(&mode, &buf);

  // rotation
  uint16_t tmp21;
  Read(&tmp21, &buf);
  rotation = static_cast<x11::RandR::Rotation>(tmp21);

  // rotations
  uint16_t tmp22;
  Read(&tmp22, &buf);
  rotations = static_cast<x11::RandR::Rotation>(tmp22);

  // num_outputs
  Read(&num_outputs, &buf);

  // num_possible_outputs
  Read(&num_possible_outputs, &buf);

  // outputs
  outputs.resize(num_outputs);
  for (auto& outputs_elem : outputs) {
    // outputs_elem
    Read(&outputs_elem, &buf);

  }

  // possible
  possible.resize(num_possible_outputs);
  for (auto& possible_elem : possible) {
    // possible_elem
    Read(&possible_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::SetCrtcConfigReply>
RandR::SetCrtcConfig(
    const RandR::SetCrtcConfigRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& crtc = request.crtc;
  auto& timestamp = request.timestamp;
  auto& config_timestamp = request.config_timestamp;
  auto& x = request.x;
  auto& y = request.y;
  auto& mode = request.mode;
  auto& rotation = request.rotation;
  auto& outputs = request.outputs;
  size_t outputs_len = outputs.size();

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 21;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // crtc
  buf.Write(&crtc);

  // timestamp
  buf.Write(&timestamp);

  // config_timestamp
  buf.Write(&config_timestamp);

  // x
  buf.Write(&x);

  // y
  buf.Write(&y);

  // mode
  buf.Write(&mode);

  // rotation
  uint16_t tmp23;
  tmp23 = static_cast<uint16_t>(rotation);
  buf.Write(&tmp23);

  // pad0
  Pad(&buf, 2);

  // outputs
  DCHECK_EQ(static_cast<size_t>(outputs_len), outputs.size());
  for (auto& outputs_elem : outputs) {
    // outputs_elem
    buf.Write(&outputs_elem);

  }

  Align(&buf, 4);

  return x11::SendRequest<RandR::SetCrtcConfigReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::SetCrtcConfigReply>
ReadReply<RandR::SetCrtcConfigReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::SetCrtcConfigReply>();

  auto& status = (*reply).status;
  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // status
  uint8_t tmp24;
  Read(&tmp24, &buf);
  status = static_cast<x11::RandR::SetConfig>(tmp24);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // pad0
  Pad(&buf, 20);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::GetCrtcGammaSizeReply>
RandR::GetCrtcGammaSize(
    const RandR::GetCrtcGammaSizeRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& crtc = request.crtc;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 22;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // crtc
  buf.Write(&crtc);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetCrtcGammaSizeReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetCrtcGammaSizeReply>
ReadReply<RandR::GetCrtcGammaSizeReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetCrtcGammaSizeReply>();

  auto& sequence = (*reply).sequence;
  auto& size = (*reply).size;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // size
  Read(&size, &buf);

  // pad1
  Pad(&buf, 22);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::GetCrtcGammaReply>
RandR::GetCrtcGamma(
    const RandR::GetCrtcGammaRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& crtc = request.crtc;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 23;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // crtc
  buf.Write(&crtc);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetCrtcGammaReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetCrtcGammaReply>
ReadReply<RandR::GetCrtcGammaReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetCrtcGammaReply>();

  auto& sequence = (*reply).sequence;
  uint16_t size{};
  auto& red = (*reply).red;
  size_t red_len = red.size();
  auto& green = (*reply).green;
  size_t green_len = green.size();
  auto& blue = (*reply).blue;
  size_t blue_len = blue.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // size
  Read(&size, &buf);

  // pad1
  Pad(&buf, 22);

  // red
  red.resize(size);
  for (auto& red_elem : red) {
    // red_elem
    Read(&red_elem, &buf);

  }

  // green
  green.resize(size);
  for (auto& green_elem : green) {
    // green_elem
    Read(&green_elem, &buf);

  }

  // blue
  blue.resize(size);
  for (auto& blue_elem : blue) {
    // blue_elem
    Read(&blue_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::SetCrtcGamma(
    const RandR::SetCrtcGammaRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& crtc = request.crtc;
  uint16_t size{};
  auto& red = request.red;
  size_t red_len = red.size();
  auto& green = request.green;
  size_t green_len = green.size();
  auto& blue = request.blue;
  size_t blue_len = blue.size();

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 24;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // crtc
  buf.Write(&crtc);

  // size
  size = blue.size();
  buf.Write(&size);

  // pad0
  Pad(&buf, 2);

  // red
  DCHECK_EQ(static_cast<size_t>(size), red.size());
  for (auto& red_elem : red) {
    // red_elem
    buf.Write(&red_elem);

  }

  // green
  DCHECK_EQ(static_cast<size_t>(size), green.size());
  for (auto& green_elem : green) {
    // green_elem
    buf.Write(&green_elem);

  }

  // blue
  DCHECK_EQ(static_cast<size_t>(size), blue.size());
  for (auto& blue_elem : blue) {
    // blue_elem
    buf.Write(&blue_elem);

  }

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::GetScreenResourcesCurrentReply>
RandR::GetScreenResourcesCurrent(
    const RandR::GetScreenResourcesCurrentRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 25;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetScreenResourcesCurrentReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetScreenResourcesCurrentReply>
ReadReply<RandR::GetScreenResourcesCurrentReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetScreenResourcesCurrentReply>();

  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;
  auto& config_timestamp = (*reply).config_timestamp;
  uint16_t num_crtcs{};
  uint16_t num_outputs{};
  uint16_t num_modes{};
  uint16_t names_len{};
  auto& crtcs = (*reply).crtcs;
  size_t crtcs_len = crtcs.size();
  auto& outputs = (*reply).outputs;
  size_t outputs_len = outputs.size();
  auto& modes = (*reply).modes;
  size_t modes_len = modes.size();
  auto& names = (*reply).names;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // config_timestamp
  Read(&config_timestamp, &buf);

  // num_crtcs
  Read(&num_crtcs, &buf);

  // num_outputs
  Read(&num_outputs, &buf);

  // num_modes
  Read(&num_modes, &buf);

  // names_len
  Read(&names_len, &buf);

  // pad1
  Pad(&buf, 8);

  // crtcs
  crtcs.resize(num_crtcs);
  for (auto& crtcs_elem : crtcs) {
    // crtcs_elem
    Read(&crtcs_elem, &buf);

  }

  // outputs
  outputs.resize(num_outputs);
  for (auto& outputs_elem : outputs) {
    // outputs_elem
    Read(&outputs_elem, &buf);

  }

  // modes
  modes.resize(num_modes);
  for (auto& modes_elem : modes) {
    // modes_elem
    {
      auto& id = modes_elem.id;
      auto& width = modes_elem.width;
      auto& height = modes_elem.height;
      auto& dot_clock = modes_elem.dot_clock;
      auto& hsync_start = modes_elem.hsync_start;
      auto& hsync_end = modes_elem.hsync_end;
      auto& htotal = modes_elem.htotal;
      auto& hskew = modes_elem.hskew;
      auto& vsync_start = modes_elem.vsync_start;
      auto& vsync_end = modes_elem.vsync_end;
      auto& vtotal = modes_elem.vtotal;
      auto& name_len = modes_elem.name_len;
      auto& mode_flags = modes_elem.mode_flags;

      // id
      Read(&id, &buf);

      // width
      Read(&width, &buf);

      // height
      Read(&height, &buf);

      // dot_clock
      Read(&dot_clock, &buf);

      // hsync_start
      Read(&hsync_start, &buf);

      // hsync_end
      Read(&hsync_end, &buf);

      // htotal
      Read(&htotal, &buf);

      // hskew
      Read(&hskew, &buf);

      // vsync_start
      Read(&vsync_start, &buf);

      // vsync_end
      Read(&vsync_end, &buf);

      // vtotal
      Read(&vtotal, &buf);

      // name_len
      Read(&name_len, &buf);

      // mode_flags
      uint32_t tmp25;
      Read(&tmp25, &buf);
      mode_flags = static_cast<x11::RandR::ModeFlag>(tmp25);

    }

  }

  // names
  names.resize(names_len);
  for (auto& names_elem : names) {
    // names_elem
    Read(&names_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::SetCrtcTransform(
    const RandR::SetCrtcTransformRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& crtc = request.crtc;
  auto& transform = request.transform;
  uint16_t filter_len{};
  auto& filter_name = request.filter_name;
  size_t filter_name_len = filter_name.size();
  auto& filter_params = request.filter_params;
  size_t filter_params_len = filter_params.size();

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 26;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // crtc
  buf.Write(&crtc);

  // transform
  {
    auto& matrix11 = transform.matrix11;
    auto& matrix12 = transform.matrix12;
    auto& matrix13 = transform.matrix13;
    auto& matrix21 = transform.matrix21;
    auto& matrix22 = transform.matrix22;
    auto& matrix23 = transform.matrix23;
    auto& matrix31 = transform.matrix31;
    auto& matrix32 = transform.matrix32;
    auto& matrix33 = transform.matrix33;

    // matrix11
    buf.Write(&matrix11);

    // matrix12
    buf.Write(&matrix12);

    // matrix13
    buf.Write(&matrix13);

    // matrix21
    buf.Write(&matrix21);

    // matrix22
    buf.Write(&matrix22);

    // matrix23
    buf.Write(&matrix23);

    // matrix31
    buf.Write(&matrix31);

    // matrix32
    buf.Write(&matrix32);

    // matrix33
    buf.Write(&matrix33);

  }

  // filter_len
  filter_len = filter_name.size();
  buf.Write(&filter_len);

  // pad0
  Pad(&buf, 2);

  // filter_name
  DCHECK_EQ(static_cast<size_t>(filter_len), filter_name.size());
  for (auto& filter_name_elem : filter_name) {
    // filter_name_elem
    buf.Write(&filter_name_elem);

  }

  // pad1
  Align(&buf, 4);

  // filter_params
  DCHECK_EQ(static_cast<size_t>(filter_params_len), filter_params.size());
  for (auto& filter_params_elem : filter_params) {
    // filter_params_elem
    buf.Write(&filter_params_elem);

  }

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::GetCrtcTransformReply>
RandR::GetCrtcTransform(
    const RandR::GetCrtcTransformRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& crtc = request.crtc;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 27;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // crtc
  buf.Write(&crtc);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetCrtcTransformReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetCrtcTransformReply>
ReadReply<RandR::GetCrtcTransformReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetCrtcTransformReply>();

  auto& sequence = (*reply).sequence;
  auto& pending_transform = (*reply).pending_transform;
  auto& has_transforms = (*reply).has_transforms;
  auto& current_transform = (*reply).current_transform;
  uint16_t pending_len{};
  uint16_t pending_nparams{};
  uint16_t current_len{};
  uint16_t current_nparams{};
  auto& pending_filter_name = (*reply).pending_filter_name;
  size_t pending_filter_name_len = pending_filter_name.size();
  auto& pending_params = (*reply).pending_params;
  size_t pending_params_len = pending_params.size();
  auto& current_filter_name = (*reply).current_filter_name;
  size_t current_filter_name_len = current_filter_name.size();
  auto& current_params = (*reply).current_params;
  size_t current_params_len = current_params.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // pending_transform
  {
    auto& matrix11 = pending_transform.matrix11;
    auto& matrix12 = pending_transform.matrix12;
    auto& matrix13 = pending_transform.matrix13;
    auto& matrix21 = pending_transform.matrix21;
    auto& matrix22 = pending_transform.matrix22;
    auto& matrix23 = pending_transform.matrix23;
    auto& matrix31 = pending_transform.matrix31;
    auto& matrix32 = pending_transform.matrix32;
    auto& matrix33 = pending_transform.matrix33;

    // matrix11
    Read(&matrix11, &buf);

    // matrix12
    Read(&matrix12, &buf);

    // matrix13
    Read(&matrix13, &buf);

    // matrix21
    Read(&matrix21, &buf);

    // matrix22
    Read(&matrix22, &buf);

    // matrix23
    Read(&matrix23, &buf);

    // matrix31
    Read(&matrix31, &buf);

    // matrix32
    Read(&matrix32, &buf);

    // matrix33
    Read(&matrix33, &buf);

  }

  // has_transforms
  Read(&has_transforms, &buf);

  // pad1
  Pad(&buf, 3);

  // current_transform
  {
    auto& matrix11 = current_transform.matrix11;
    auto& matrix12 = current_transform.matrix12;
    auto& matrix13 = current_transform.matrix13;
    auto& matrix21 = current_transform.matrix21;
    auto& matrix22 = current_transform.matrix22;
    auto& matrix23 = current_transform.matrix23;
    auto& matrix31 = current_transform.matrix31;
    auto& matrix32 = current_transform.matrix32;
    auto& matrix33 = current_transform.matrix33;

    // matrix11
    Read(&matrix11, &buf);

    // matrix12
    Read(&matrix12, &buf);

    // matrix13
    Read(&matrix13, &buf);

    // matrix21
    Read(&matrix21, &buf);

    // matrix22
    Read(&matrix22, &buf);

    // matrix23
    Read(&matrix23, &buf);

    // matrix31
    Read(&matrix31, &buf);

    // matrix32
    Read(&matrix32, &buf);

    // matrix33
    Read(&matrix33, &buf);

  }

  // pad2
  Pad(&buf, 4);

  // pending_len
  Read(&pending_len, &buf);

  // pending_nparams
  Read(&pending_nparams, &buf);

  // current_len
  Read(&current_len, &buf);

  // current_nparams
  Read(&current_nparams, &buf);

  // pending_filter_name
  pending_filter_name.resize(pending_len);
  for (auto& pending_filter_name_elem : pending_filter_name) {
    // pending_filter_name_elem
    Read(&pending_filter_name_elem, &buf);

  }

  // pad3
  Align(&buf, 4);

  // pending_params
  pending_params.resize(pending_nparams);
  for (auto& pending_params_elem : pending_params) {
    // pending_params_elem
    Read(&pending_params_elem, &buf);

  }

  // current_filter_name
  current_filter_name.resize(current_len);
  for (auto& current_filter_name_elem : current_filter_name) {
    // current_filter_name_elem
    Read(&current_filter_name_elem, &buf);

  }

  // pad4
  Align(&buf, 4);

  // current_params
  current_params.resize(current_nparams);
  for (auto& current_params_elem : current_params) {
    // current_params_elem
    Read(&current_params_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::GetPanningReply>
RandR::GetPanning(
    const RandR::GetPanningRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& crtc = request.crtc;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 28;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // crtc
  buf.Write(&crtc);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetPanningReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetPanningReply>
ReadReply<RandR::GetPanningReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetPanningReply>();

  auto& status = (*reply).status;
  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;
  auto& left = (*reply).left;
  auto& top = (*reply).top;
  auto& width = (*reply).width;
  auto& height = (*reply).height;
  auto& track_left = (*reply).track_left;
  auto& track_top = (*reply).track_top;
  auto& track_width = (*reply).track_width;
  auto& track_height = (*reply).track_height;
  auto& border_left = (*reply).border_left;
  auto& border_top = (*reply).border_top;
  auto& border_right = (*reply).border_right;
  auto& border_bottom = (*reply).border_bottom;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // status
  uint8_t tmp26;
  Read(&tmp26, &buf);
  status = static_cast<x11::RandR::SetConfig>(tmp26);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // left
  Read(&left, &buf);

  // top
  Read(&top, &buf);

  // width
  Read(&width, &buf);

  // height
  Read(&height, &buf);

  // track_left
  Read(&track_left, &buf);

  // track_top
  Read(&track_top, &buf);

  // track_width
  Read(&track_width, &buf);

  // track_height
  Read(&track_height, &buf);

  // border_left
  Read(&border_left, &buf);

  // border_top
  Read(&border_top, &buf);

  // border_right
  Read(&border_right, &buf);

  // border_bottom
  Read(&border_bottom, &buf);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::SetPanningReply>
RandR::SetPanning(
    const RandR::SetPanningRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& crtc = request.crtc;
  auto& timestamp = request.timestamp;
  auto& left = request.left;
  auto& top = request.top;
  auto& width = request.width;
  auto& height = request.height;
  auto& track_left = request.track_left;
  auto& track_top = request.track_top;
  auto& track_width = request.track_width;
  auto& track_height = request.track_height;
  auto& border_left = request.border_left;
  auto& border_top = request.border_top;
  auto& border_right = request.border_right;
  auto& border_bottom = request.border_bottom;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 29;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // crtc
  buf.Write(&crtc);

  // timestamp
  buf.Write(&timestamp);

  // left
  buf.Write(&left);

  // top
  buf.Write(&top);

  // width
  buf.Write(&width);

  // height
  buf.Write(&height);

  // track_left
  buf.Write(&track_left);

  // track_top
  buf.Write(&track_top);

  // track_width
  buf.Write(&track_width);

  // track_height
  buf.Write(&track_height);

  // border_left
  buf.Write(&border_left);

  // border_top
  buf.Write(&border_top);

  // border_right
  buf.Write(&border_right);

  // border_bottom
  buf.Write(&border_bottom);

  Align(&buf, 4);

  return x11::SendRequest<RandR::SetPanningReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::SetPanningReply>
ReadReply<RandR::SetPanningReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::SetPanningReply>();

  auto& status = (*reply).status;
  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // status
  uint8_t tmp27;
  Read(&tmp27, &buf);
  status = static_cast<x11::RandR::SetConfig>(tmp27);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::SetOutputPrimary(
    const RandR::SetOutputPrimaryRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;
  auto& output = request.output;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 30;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  // output
  buf.Write(&output);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::GetOutputPrimaryReply>
RandR::GetOutputPrimary(
    const RandR::GetOutputPrimaryRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 31;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetOutputPrimaryReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetOutputPrimaryReply>
ReadReply<RandR::GetOutputPrimaryReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetOutputPrimaryReply>();

  auto& sequence = (*reply).sequence;
  auto& output = (*reply).output;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // output
  Read(&output, &buf);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::GetProvidersReply>
RandR::GetProviders(
    const RandR::GetProvidersRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 32;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetProvidersReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetProvidersReply>
ReadReply<RandR::GetProvidersReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetProvidersReply>();

  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;
  uint16_t num_providers{};
  auto& providers = (*reply).providers;
  size_t providers_len = providers.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // num_providers
  Read(&num_providers, &buf);

  // pad1
  Pad(&buf, 18);

  // providers
  providers.resize(num_providers);
  for (auto& providers_elem : providers) {
    // providers_elem
    Read(&providers_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::GetProviderInfoReply>
RandR::GetProviderInfo(
    const RandR::GetProviderInfoRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& provider = request.provider;
  auto& config_timestamp = request.config_timestamp;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 33;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // provider
  buf.Write(&provider);

  // config_timestamp
  buf.Write(&config_timestamp);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetProviderInfoReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetProviderInfoReply>
ReadReply<RandR::GetProviderInfoReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetProviderInfoReply>();

  auto& status = (*reply).status;
  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;
  auto& capabilities = (*reply).capabilities;
  uint16_t num_crtcs{};
  uint16_t num_outputs{};
  uint16_t num_associated_providers{};
  uint16_t name_len{};
  auto& crtcs = (*reply).crtcs;
  size_t crtcs_len = crtcs.size();
  auto& outputs = (*reply).outputs;
  size_t outputs_len = outputs.size();
  auto& associated_providers = (*reply).associated_providers;
  size_t associated_providers_len = associated_providers.size();
  auto& associated_capability = (*reply).associated_capability;
  size_t associated_capability_len = associated_capability.size();
  auto& name = (*reply).name;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // status
  Read(&status, &buf);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // capabilities
  uint32_t tmp28;
  Read(&tmp28, &buf);
  capabilities = static_cast<x11::RandR::ProviderCapability>(tmp28);

  // num_crtcs
  Read(&num_crtcs, &buf);

  // num_outputs
  Read(&num_outputs, &buf);

  // num_associated_providers
  Read(&num_associated_providers, &buf);

  // name_len
  Read(&name_len, &buf);

  // pad0
  Pad(&buf, 8);

  // crtcs
  crtcs.resize(num_crtcs);
  for (auto& crtcs_elem : crtcs) {
    // crtcs_elem
    Read(&crtcs_elem, &buf);

  }

  // outputs
  outputs.resize(num_outputs);
  for (auto& outputs_elem : outputs) {
    // outputs_elem
    Read(&outputs_elem, &buf);

  }

  // associated_providers
  associated_providers.resize(num_associated_providers);
  for (auto& associated_providers_elem : associated_providers) {
    // associated_providers_elem
    Read(&associated_providers_elem, &buf);

  }

  // associated_capability
  associated_capability.resize(num_associated_providers);
  for (auto& associated_capability_elem : associated_capability) {
    // associated_capability_elem
    Read(&associated_capability_elem, &buf);

  }

  // name
  name.resize(name_len);
  for (auto& name_elem : name) {
    // name_elem
    Read(&name_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::SetProviderOffloadSink(
    const RandR::SetProviderOffloadSinkRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& provider = request.provider;
  auto& sink_provider = request.sink_provider;
  auto& config_timestamp = request.config_timestamp;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 34;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // provider
  buf.Write(&provider);

  // sink_provider
  buf.Write(&sink_provider);

  // config_timestamp
  buf.Write(&config_timestamp);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<void>
RandR::SetProviderOutputSource(
    const RandR::SetProviderOutputSourceRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& provider = request.provider;
  auto& source_provider = request.source_provider;
  auto& config_timestamp = request.config_timestamp;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 35;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // provider
  buf.Write(&provider);

  // source_provider
  buf.Write(&source_provider);

  // config_timestamp
  buf.Write(&config_timestamp);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::ListProviderPropertiesReply>
RandR::ListProviderProperties(
    const RandR::ListProviderPropertiesRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& provider = request.provider;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 36;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // provider
  buf.Write(&provider);

  Align(&buf, 4);

  return x11::SendRequest<RandR::ListProviderPropertiesReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::ListProviderPropertiesReply>
ReadReply<RandR::ListProviderPropertiesReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::ListProviderPropertiesReply>();

  auto& sequence = (*reply).sequence;
  uint16_t num_atoms{};
  auto& atoms = (*reply).atoms;
  size_t atoms_len = atoms.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // num_atoms
  Read(&num_atoms, &buf);

  // pad1
  Pad(&buf, 22);

  // atoms
  atoms.resize(num_atoms);
  for (auto& atoms_elem : atoms) {
    // atoms_elem
    Read(&atoms_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::QueryProviderPropertyReply>
RandR::QueryProviderProperty(
    const RandR::QueryProviderPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& provider = request.provider;
  auto& property = request.property;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 37;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // provider
  buf.Write(&provider);

  // property
  buf.Write(&property);

  Align(&buf, 4);

  return x11::SendRequest<RandR::QueryProviderPropertyReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::QueryProviderPropertyReply>
ReadReply<RandR::QueryProviderPropertyReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::QueryProviderPropertyReply>();

  auto& sequence = (*reply).sequence;
  auto& pending = (*reply).pending;
  auto& range = (*reply).range;
  auto& immutable = (*reply).immutable;
  auto& valid_values = (*reply).valid_values;
  size_t valid_values_len = valid_values.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // pending
  Read(&pending, &buf);

  // range
  Read(&range, &buf);

  // immutable
  Read(&immutable, &buf);

  // pad1
  Pad(&buf, 21);

  // valid_values
  valid_values.resize(length);
  for (auto& valid_values_elem : valid_values) {
    // valid_values_elem
    Read(&valid_values_elem, &buf);

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::ConfigureProviderProperty(
    const RandR::ConfigureProviderPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& provider = request.provider;
  auto& property = request.property;
  auto& pending = request.pending;
  auto& range = request.range;
  auto& values = request.values;
  size_t values_len = values.size();

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 38;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // provider
  buf.Write(&provider);

  // property
  buf.Write(&property);

  // pending
  buf.Write(&pending);

  // range
  buf.Write(&range);

  // pad0
  Pad(&buf, 2);

  // values
  DCHECK_EQ(static_cast<size_t>(values_len), values.size());
  for (auto& values_elem : values) {
    // values_elem
    buf.Write(&values_elem);

  }

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<void>
RandR::ChangeProviderProperty(
    const RandR::ChangeProviderPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& provider = request.provider;
  auto& property = request.property;
  auto& type = request.type;
  auto& format = request.format;
  auto& mode = request.mode;
  auto& num_items = request.num_items;
  auto& data = request.data;
  size_t data_len = data ? data->size() : 0;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 39;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // provider
  buf.Write(&provider);

  // property
  buf.Write(&property);

  // type
  buf.Write(&type);

  // format
  buf.Write(&format);

  // mode
  buf.Write(&mode);

  // pad0
  Pad(&buf, 2);

  // num_items
  buf.Write(&num_items);

  // data
  buf.AppendBuffer(data, (num_items) * ((format) / (8)));

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<void>
RandR::DeleteProviderProperty(
    const RandR::DeleteProviderPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& provider = request.provider;
  auto& property = request.property;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 40;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // provider
  buf.Write(&provider);

  // property
  buf.Write(&property);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::GetProviderPropertyReply>
RandR::GetProviderProperty(
    const RandR::GetProviderPropertyRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& provider = request.provider;
  auto& property = request.property;
  auto& type = request.type;
  auto& long_offset = request.long_offset;
  auto& long_length = request.long_length;
  auto& c_delete = request.c_delete;
  auto& pending = request.pending;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 41;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // provider
  buf.Write(&provider);

  // property
  buf.Write(&property);

  // type
  buf.Write(&type);

  // long_offset
  buf.Write(&long_offset);

  // long_length
  buf.Write(&long_length);

  // c_delete
  buf.Write(&c_delete);

  // pending
  buf.Write(&pending);

  // pad0
  Pad(&buf, 2);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetProviderPropertyReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetProviderPropertyReply>
ReadReply<RandR::GetProviderPropertyReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetProviderPropertyReply>();

  auto& format = (*reply).format;
  auto& sequence = (*reply).sequence;
  auto& type = (*reply).type;
  auto& bytes_after = (*reply).bytes_after;
  auto& num_items = (*reply).num_items;
  auto& data = (*reply).data;
  size_t data_len = data ? data->size() : 0;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // format
  Read(&format, &buf);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // type
  Read(&type, &buf);

  // bytes_after
  Read(&bytes_after, &buf);

  // num_items
  Read(&num_items, &buf);

  // pad0
  Pad(&buf, 12);

  // data
  data = buffer->ReadAndAdvance((num_items) * ((format) / (8)));

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<RandR::GetMonitorsReply>
RandR::GetMonitors(
    const RandR::GetMonitorsRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;
  auto& get_active = request.get_active;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 42;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  // get_active
  buf.Write(&get_active);

  Align(&buf, 4);

  return x11::SendRequest<RandR::GetMonitorsReply>(connection_, &buf, false);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::GetMonitorsReply>
ReadReply<RandR::GetMonitorsReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::GetMonitorsReply>();

  auto& sequence = (*reply).sequence;
  auto& timestamp = (*reply).timestamp;
  uint32_t nMonitors{};
  auto& nOutputs = (*reply).nOutputs;
  auto& monitors = (*reply).monitors;
  size_t monitors_len = monitors.size();

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // pad0
  Pad(&buf, 1);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // timestamp
  Read(&timestamp, &buf);

  // nMonitors
  Read(&nMonitors, &buf);

  // nOutputs
  Read(&nOutputs, &buf);

  // pad1
  Pad(&buf, 12);

  // monitors
  monitors.resize(nMonitors);
  for (auto& monitors_elem : monitors) {
    // monitors_elem
    {
      auto& name = monitors_elem.name;
      auto& primary = monitors_elem.primary;
      auto& automatic = monitors_elem.automatic;
      uint16_t nOutput{};
      auto& x = monitors_elem.x;
      auto& y = monitors_elem.y;
      auto& width = monitors_elem.width;
      auto& height = monitors_elem.height;
      auto& width_in_millimeters = monitors_elem.width_in_millimeters;
      auto& height_in_millimeters = monitors_elem.height_in_millimeters;
      auto& outputs = monitors_elem.outputs;
      size_t outputs_len = outputs.size();

      // name
      Read(&name, &buf);

      // primary
      Read(&primary, &buf);

      // automatic
      Read(&automatic, &buf);

      // nOutput
      Read(&nOutput, &buf);

      // x
      Read(&x, &buf);

      // y
      Read(&y, &buf);

      // width
      Read(&width, &buf);

      // height
      Read(&height, &buf);

      // width_in_millimeters
      Read(&width_in_millimeters, &buf);

      // height_in_millimeters
      Read(&height_in_millimeters, &buf);

      // outputs
      outputs.resize(nOutput);
      for (auto& outputs_elem : outputs) {
        // outputs_elem
        Read(&outputs_elem, &buf);

      }

    }

  }

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::SetMonitor(
    const RandR::SetMonitorRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;
  auto& monitorinfo = request.monitorinfo;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 43;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  // monitorinfo
  {
    auto& name = monitorinfo.name;
    auto& primary = monitorinfo.primary;
    auto& automatic = monitorinfo.automatic;
    uint16_t nOutput{};
    auto& x = monitorinfo.x;
    auto& y = monitorinfo.y;
    auto& width = monitorinfo.width;
    auto& height = monitorinfo.height;
    auto& width_in_millimeters = monitorinfo.width_in_millimeters;
    auto& height_in_millimeters = monitorinfo.height_in_millimeters;
    auto& outputs = monitorinfo.outputs;
    size_t outputs_len = outputs.size();

    // name
    buf.Write(&name);

    // primary
    buf.Write(&primary);

    // automatic
    buf.Write(&automatic);

    // nOutput
    nOutput = outputs.size();
    buf.Write(&nOutput);

    // x
    buf.Write(&x);

    // y
    buf.Write(&y);

    // width
    buf.Write(&width);

    // height
    buf.Write(&height);

    // width_in_millimeters
    buf.Write(&width_in_millimeters);

    // height_in_millimeters
    buf.Write(&height_in_millimeters);

    // outputs
    DCHECK_EQ(static_cast<size_t>(nOutput), outputs.size());
    for (auto& outputs_elem : outputs) {
      // outputs_elem
      buf.Write(&outputs_elem);

    }

  }

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<void>
RandR::DeleteMonitor(
    const RandR::DeleteMonitorRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;
  auto& name = request.name;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 44;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  // name
  buf.Write(&name);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

Future<RandR::CreateLeaseReply>
RandR::CreateLease(
    const RandR::CreateLeaseRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& window = request.window;
  auto& lid = request.lid;
  uint16_t num_crtcs{};
  uint16_t num_outputs{};
  auto& crtcs = request.crtcs;
  size_t crtcs_len = crtcs.size();
  auto& outputs = request.outputs;
  size_t outputs_len = outputs.size();

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 45;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // window
  buf.Write(&window);

  // lid
  buf.Write(&lid);

  // num_crtcs
  num_crtcs = crtcs.size();
  buf.Write(&num_crtcs);

  // num_outputs
  num_outputs = outputs.size();
  buf.Write(&num_outputs);

  // crtcs
  DCHECK_EQ(static_cast<size_t>(num_crtcs), crtcs.size());
  for (auto& crtcs_elem : crtcs) {
    // crtcs_elem
    buf.Write(&crtcs_elem);

  }

  // outputs
  DCHECK_EQ(static_cast<size_t>(num_outputs), outputs.size());
  for (auto& outputs_elem : outputs) {
    // outputs_elem
    buf.Write(&outputs_elem);

  }

  Align(&buf, 4);

  return x11::SendRequest<RandR::CreateLeaseReply>(connection_, &buf, true);
}

namespace detail {
template<> COMPONENT_EXPORT(X11)
std::unique_ptr<RandR::CreateLeaseReply>
ReadReply<RandR::CreateLeaseReply>(ReadBuffer* buffer) {
  auto& buf = *buffer;
  auto reply = std::make_unique<RandR::CreateLeaseReply>();

  auto& nfd = (*reply).nfd;
  auto& sequence = (*reply).sequence;
  auto& master_fd = (*reply).master_fd;

  // response_type
  uint8_t response_type;
  Read(&response_type, &buf);

  // nfd
  Read(&nfd, &buf);

  // sequence
  Read(&sequence, &buf);

  // length
  uint32_t length;
  Read(&length, &buf);

  // master_fd
  master_fd = base::ScopedFD(buf.TakeFd());

  // pad0
  Pad(&buf, 24);

  Align(&buf, 4);
  DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);

  return reply;
}
}  // namespace detail

Future<void>
RandR::FreeLease(
    const RandR::FreeLeaseRequest& request) {
  if (!connection_->Ready() || !present())
    return {};

  WriteBuffer buf;

  auto& lid = request.lid;
  auto& terminate = request.terminate;

  // major_opcode
  uint8_t major_opcode = info_.major_opcode;
  buf.Write(&major_opcode);

  // minor_opcode
  uint8_t minor_opcode = 46;
  buf.Write(&minor_opcode);

  // length
  // Caller fills in length for writes.
  Pad(&buf, sizeof(uint16_t));

  // lid
  buf.Write(&lid);

  // terminate
  buf.Write(&terminate);

  Align(&buf, 4);

  return x11::SendRequest<void>(connection_, &buf, false);
}

}  // namespace x11
