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 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
// 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 <wayland-server-core.h>
#include <wayland-server-protocol-core.h>
#include <cstring>
#include "base/compiler_specific.h"
#include "base/task/single_thread_task_runner.h"
#include "components/exo/surface.h"
#include "components/exo/wayland/server_util.h"
#include "components/exo/wayland/wayland_display_observer.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(const display::Display& display)
: id_(display.id()), metrics_(display) {}
WaylandDisplayOutput::~WaylandDisplayOutput() {
// Empty the output_ids_ so that Unregister will be no op.
auto ids = std::move(output_ids_);
for (auto pair : ids) {
if (wl_resource_get_version(pair.second) >=
WL_OUTPUT_RELEASE_SINCE_VERSION) {
// At version >= 3, clients should send wl_output.release to let server
// know that an output object will be unused. Remove the user_data and
// destructor, keep wl_resource alive as there could be other requests
// referencing it asynchronously.
DestroyUserData<WaylandDisplayHandler>(pair.second);
wl_resource_set_user_data(pair.second, nullptr);
wl_resource_set_destructor(pair.second, nullptr);
} else {
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;
}
}
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 (UNSAFE_TODO(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;
}
void WaylandDisplayOutput::SendDisplayMetricsChanges(
const display::Display& display,
uint32_t changed_metrics) {
CHECK_EQ(display.id(), id_);
// Update output metrics before propagating display changes.
metrics_ = OutputMetrics(display);
for (auto& pair : output_ids_) {
if (auto* handler = GetUserDataAs<WaylandDisplayHandler>(pair.second)) {
handler->SendDisplayMetricsChanges(display, changed_metrics);
}
}
}
void WaylandDisplayOutput::SendOutputActivated() {
for (auto& pair : output_ids_) {
auto* handler = GetUserDataAs<WaylandDisplayHandler>(pair.second);
CHECK(handler);
handler->SendDisplayActivated();
}
}
} // namespace wayland
} // namespace exo
|