1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
// Copyright 2018 The Chromium Authors
// 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/task/single_thread_task_runner.h"
#include "components/exo/surface.h"
#include "components/exo/wayland/server_util.h"
namespace exo {
namespace wayland {
namespace {
void DoDelete(WaylandDisplayOutput* output, int retry_count) {
// Retry if a client hasn't released the output yet, or if no client has
// even made the initial binding yet.
if (output->output_counts() > 0 || !output->had_registered_output()) {
if (retry_count > 0) {
// If we can't post the task successfully, just delete the output
// resource now, otherwise we would leak memory.
if (base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, base::BindOnce(&DoDelete, output, retry_count - 1),
WaylandDisplayOutput::kDeleteTaskDelay)) {
return;
} else {
LOG(WARNING) << "Failed to post delayed deletion task for "
"WaylandDisplayOutput with display id="
<< output->id()
<< " and remaining retry count: " << retry_count;
}
} else {
LOG(WARNING)
<< "Timed out waiting for clients to unbind registered output for id="
<< output->id()
<< " with remaining bound outputs=" << output->output_counts();
}
}
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_);
}
is_destructing_ = true;
if (!base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, base::BindOnce(&DoDelete, this, kDeleteRetries),
kDeleteTaskDelay)) {
// If we can't schedule the delete task, just delete now to not leak memory.
LOG(WARNING) << "Failed to post initial delayed deletion task for "
"WaylandDisplayOutput with display id="
<< id();
delete this;
}
}
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));
had_registered_output_ = true;
if (is_destructing_) {
return;
}
// Notify All wl surfaces that a new output was added.
wl_client_for_each_resource(
client,
[](wl_resource* resource, void*) {
if (std::strcmp("wl_surface", wl_resource_get_class(resource)) == 0) {
if (auto* surface = GetUserDataAs<Surface>(resource)) {
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
|