chromium/components/exo/wayland/test/test_client.h

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_EXO_WAYLAND_TEST_TEST_CLIENT_H_
#define COMPONENTS_EXO_WAYLAND_TEST_TEST_CLIENT_H_

#include <memory>
#include <string>

#include "base/containers/flat_map.h"
#include "base/threading/thread_checker.h"
#include "components/exo/wayland/clients/globals.h"
#include "components/exo/wayland/test/shm_buffer_factory.h"

namespace exo::wayland::test {

// Wayland client used by WaylandServerTest.
// You can also derive from this class to extend the client if needed. Please
// also see WaylandServerTest::InitOnClientThread().
//
// Thread affinity: Lives exclusively on the client thread.
class TestClient {
 public:
  TestClient();

  TestClient(const TestClient&) = delete;
  TestClient& operator=(const TestClient&) = delete;

  virtual ~TestClient();

  // Initializes connection to the server side and globals.
  bool Init(const std::string& wayland_socket,
            base::flat_map<std::string, uint32_t> global_versions = {});

  void Roundtrip() { wl_display_roundtrip(display()); }

  wl_display* display() {
    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
    return display_.get();
  }

  const clients::Globals& globals() const {
    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
    return globals_;
  }

  clients::Globals& globals() {
    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
    return globals_;
  }

  // Convenient getters of globals.
  wl_output* output() { return globals().outputs.back().get(); }
  wl_compositor* compositor() { return globals().compositor.get(); }
  wl_shm* shm() { return globals().shm.get(); }
  wp_presentation* presentation() { return globals().presentation.get(); }
  zwp_linux_dmabuf_v1* linux_dmabuf() { return globals().linux_dmabuf.get(); }
  wl_shell* shell() { return globals().shell.get(); }
  wl_seat* seat() { return globals().seat.get(); }
  wl_subcompositor* subcompositor() { return globals().subcompositor.get(); }
  zaura_shell* aura_shell() { return globals().aura_shell.get(); }
  zaura_output* aura_output() { return globals().aura_outputs.back().get(); }
  zaura_output_manager* aura_output_manager() {
    return globals().aura_output_manager.get();
  }
  zaura_output_manager_v2* aura_output_manager_v2() {
    return globals().aura_output_manager_v2.get();
  }
  xdg_wm_base* xdg_wm_base() { return globals().xdg_wm_base.get(); }
  zwp_fullscreen_shell_v1* fullscreen_shell() {
    return globals().fullscreen_shell.get();
  }
  zwp_input_timestamps_manager_v1* input_timestamps_manager() {
    return globals().input_timestamps_manager.get();
  }
  zwp_linux_explicit_synchronization_v1* linux_explicit_synchronization() {
    return globals().linux_explicit_synchronization.get();
  }
  zcr_vsync_feedback_v1* vsync_feedback() {
    return globals().vsync_feedback.get();
  }
  zcr_color_manager_v1* color_manager() {
    return globals().color_manager.get();
  }
  zcr_stylus_v2* stylus() { return globals().stylus.get(); }
  zcr_remote_shell_v1* cr_remote_shell_v1() {
    return globals().cr_remote_shell_v1.get();
  }
  zcr_remote_shell_v2* cr_remote_shell_v2() {
    return globals().cr_remote_shell_v2.get();
  }
  surface_augmenter* surface_augmenter() {
    return globals().surface_augmenter.get();
  }
  wl_data_device_manager* data_device_manager() {
    return globals().data_device_manager.get();
  }

  //////////////////////////////////////////////////////////////////////////////
  // Buffer creation support.

  // Initializes `shm_buffer_factory_`.
  bool InitShmBufferFactory(int32_t pool_size);

  // Must call InitShmBufferFactory() beforehand.
  ShmBufferFactory* shm_buffer_factory() { return shm_buffer_factory_.get(); }

  //////////////////////////////////////////////////////////////////////////////
  // CustomData supports attaching customized data to the client.
  class CustomData {
   public:
    CustomData() = default;

    CustomData(const CustomData&) = delete;
    CustomData& operator=(const CustomData&) = delete;

    virtual ~CustomData() = default;
  };

  template <std::derived_from<CustomData> T>
  T* set_data(std::unique_ptr<T> data) {
    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
    auto* r = data.get();
    data_ = std::move(data);
    return r;
  }

  template <class DataType>
  DataType* GetDataAs() {
    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
    return static_cast<DataType*>(data_.get());
  }

  void DestroyData() { data_.reset(); }

 protected:
  THREAD_CHECKER(thread_checker_);

  std::unique_ptr<wl_display> display_;
  clients::Globals globals_;

  std::unique_ptr<ShmBufferFactory> shm_buffer_factory_;

  std::unique_ptr<CustomData> data_;
};

}  // namespace exo::wayland::test

#endif  // COMPONENTS_EXO_WAYLAND_TEST_TEST_CLIENT_H_