File: wayland_display_output.cc

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (157 lines) | stat: -rw-r--r-- 5,102 bytes parent folder | download | duplicates (5)
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