blob: 796e06354669f2038d63349a0cac6f18ba9f747a [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/exo/wayland/wayland_display_output.h"
#include <cstring>
#include <wayland-server-core.h>
#include <wayland-server-protocol-core.h>
#include "base/containers/cxx20_erase.h"
#include "base/logging.h"
#include "base/task/thread_pool.h"
#include "components/exo/surface.h"
#include "components/exo/wayland/server_util.h"
namespace exo {
namespace wayland {
namespace {
base::TimeDelta kDeleteTaskDelay = base::Seconds(3);
void DoDelete(WaylandDisplayOutput* output, int retry_count) {
if (retry_count > 0 && output->output_counts() > 0) {
// Try a few times to give a client chance to release it.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::BindOnce(&DoDelete, output, retry_count - 1),
kDeleteTaskDelay);
} else {
delete output;
}
}
} // namespace
WaylandDisplayOutput::WaylandDisplayOutput(int64_t id) : id_(id) {}
WaylandDisplayOutput::~WaylandDisplayOutput() {
// Empty the output_ids_ so that Unregister will be no op.
auto ids = std::move(output_ids_);
for (auto pair : ids)
wl_resource_destroy(pair.second);
if (global_)
wl_global_destroy(global_);
}
void WaylandDisplayOutput::OnDisplayRemoved() {
if (global_)
wl_global_remove(global_);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::BindOnce(&DoDelete, this, /*retry_count=*/3),
kDeleteTaskDelay);
}
int64_t WaylandDisplayOutput::id() const {
return id_;
}
void WaylandDisplayOutput::set_global(wl_global* global) {
global_ = global;
}
void WaylandDisplayOutput::UnregisterOutput(wl_resource* output_resource) {
base::EraseIf(output_ids_, [output_resource](auto& pair) {
return pair.second == output_resource;
});
}
void WaylandDisplayOutput::RegisterOutput(wl_resource* output_resource) {
auto* client = wl_resource_get_client(output_resource);
output_ids_.insert(std::make_pair(client, output_resource));
// Notify All wl surfaces that a new output was added.
wl_client_for_each_resource(
client,
[](wl_resource* resource, void*) {
constexpr char kWlSurfaceClass[] = "wl_surface";
const char* class_name = wl_resource_get_class(resource);
if (std::strcmp(kWlSurfaceClass, class_name) == 0) {
auto* surface = GetUserDataAs<Surface>(resource);
if (surface)
surface->OnNewOutputAdded();
}
return WL_ITERATOR_CONTINUE;
},
nullptr);
}
wl_resource* WaylandDisplayOutput::GetOutputResourceForClient(
wl_client* client) {
auto iter = output_ids_.find(client);
if (iter == output_ids_.end())
return nullptr;
return iter->second;
}
} // namespace wayland
} // namespace exo