chromium/components/exo/wayland/client_tracker.h

// Copyright 2023 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_CLIENT_TRACKER_H_
#define COMPONENTS_EXO_WAYLAND_CLIENT_TRACKER_H_

#include <memory>

#include <wayland-server-protocol-core.h>

#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"

struct wl_client;
struct wl_display;

namespace exo::wayland {

// Utility class to keep track of the lifetime of wl_client. This is necessary
// as resources owned by wl_client are freed in the process of destruction, and
// accessing client resources should not happen after this time (see
// crbug.com/1433187). All resources and associated user data are destroyed and
// freed before the wl_client is itself deleted.
class ClientTracker {
 public:
  explicit ClientTracker(wl_display* wl_display);
  virtual ~ClientTracker();

  // Returns true if `client` has begun destruction. Client resources should not
  // be queried after this point.
  bool IsClientDestroyed(wl_client* client) const;

  int NumClientsTrackedForTesting() const;

 private:
  // Listener called when the wl_client has been successfully created for
  // `wl_display_` and immediately when the clients begins destruction (before
  // associated resources have been freed).
  struct ClientListener {
    ClientListener(ClientTracker* tracker, wl_notify_func_t notify);
    wl_listener listener;
    raw_ptr<ClientTracker> tracker;
  };

  // Called when a wl_client has successfully been created for `wl_display_`.
  static void OnClientCreated(struct wl_listener* listener, void* data);

  // Called when a wl_client associated with the listener begins destruction.
  static void OnClientDestroyed(struct wl_listener* listener, void* data);

  // Handles the `OnClientCreated()` event for clients associated with this
  // tracker instance.
  void HandleClientCreated(wl_client* client);

  // Handles the `OnClientDestroyed()` event for clients associated with this
  // tracker instance.
  void HandleClientDestroyed(wl_client* client);

  raw_ptr<wl_display> wl_display_;

  ClientListener client_created_listener_;

  // Presence in `client_destroyed_listeners_` indicates the client has been
  // created and has yet to be destroyed.
  base::flat_map<wl_client*, std::unique_ptr<ClientListener>>
      client_destroyed_listeners_;
};

}  // namespace exo::wayland

#endif  // COMPONENTS_EXO_WAYLAND_CLIENT_TRACKER_H_