| // 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. |
| |
| #ifdef UNSAFE_BUFFERS_BUILD |
| // TODO(crbug.com/40285824): Remove this and convert code to safer constructs. |
| #pragma allow_unsafe_buffers |
| #endif |
| |
| #include "components/exo/wayland/client_tracker.h" |
| |
| namespace exo::wayland { |
| |
| ClientTracker::ClientTracker(wl_display* wl_display) |
| : wl_display_(wl_display), |
| client_created_listener_(this, &ClientTracker::OnClientCreated) { |
| wl_display_add_client_created_listener(wl_display, |
| &client_created_listener_.listener); |
| } |
| |
| ClientTracker::~ClientTracker() { |
| while (client_destroyed_listeners_.size() > 0) { |
| auto it = client_destroyed_listeners_.begin(); |
| wl_list_remove(&it->second->listener.link); |
| client_destroyed_listeners_.erase(it->first); |
| } |
| // Remove the listener from the display's destroy signal. |
| wl_list_remove(&client_created_listener_.listener.link); |
| } |
| |
| bool ClientTracker::IsClientDestroyed(wl_client* client) const { |
| return client_destroyed_listeners_.find(client) == |
| client_destroyed_listeners_.end(); |
| } |
| |
| int ClientTracker::NumClientsTrackedForTesting() const { |
| return client_destroyed_listeners_.size(); |
| } |
| |
| ClientTracker::ClientListener::ClientListener(ClientTracker* tracker, |
| wl_notify_func_t notify) |
| : tracker(tracker) { |
| listener.notify = notify; |
| } |
| |
| // static. |
| void ClientTracker::OnClientCreated(struct wl_listener* listener, void* data) { |
| ClientListener* client_created_listener = wl_container_of( |
| listener, /*sample=*/client_created_listener, /*member=*/listener); |
| wl_client* client = static_cast<wl_client*>(data); |
| ClientTracker* tracker = client_created_listener->tracker; |
| tracker->HandleClientCreated(client); |
| } |
| |
| // static. |
| void ClientTracker::OnClientDestroyed(struct wl_listener* listener, |
| void* data) { |
| ClientListener* client_destroyed_listener = wl_container_of( |
| listener, /*sample=*/client_destroyed_listener, /*member=*/listener); |
| wl_client* client = static_cast<wl_client*>(data); |
| ClientTracker* tracker = client_destroyed_listener->tracker; |
| tracker->HandleClientDestroyed(client); |
| } |
| |
| void ClientTracker::HandleClientCreated(wl_client* client) { |
| // Set up the destruction listener for the newly created client. |
| client_destroyed_listeners_.emplace( |
| client, std::make_unique<ClientListener>( |
| this, &ClientTracker::OnClientDestroyed)); |
| auto& client_destroyed_listener = client_destroyed_listeners_.at(client); |
| wl_client_add_destroy_listener(client, &client_destroyed_listener->listener); |
| } |
| |
| void ClientTracker::HandleClientDestroyed(wl_client* client) { |
| // Remove the listener from the client's destroy signal. |
| auto& client_destroyed_listener = client_destroyed_listeners_.at(client); |
| wl_list_remove(&client_destroyed_listener->listener.link); |
| client_destroyed_listeners_.erase(client); |
| } |
| |
| } // namespace exo::wayland |