wayland_display_observer.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/exo/wayland/wayland_display_observer.h"
  5. #include <wayland-server-core.h>
  6. #include <xdg-output-unstable-v1-server-protocol.h>
  7. #include <string>
  8. #include "chrome-color-management-server-protocol.h"
  9. #include "components/exo/wayland/server_util.h"
  10. #include "components/exo/wayland/wayland_display_output.h"
  11. #include "components/exo/wayland/wayland_display_util.h"
  12. #include "components/exo/wayland/zcr_color_manager.h"
  13. #include "components/exo/wm_helper.h"
  14. #include "ui/display/display_observer.h"
  15. #include "ui/display/manager/managed_display_info.h"
  16. #include "ui/display/screen.h"
  17. #include "wayland-server-protocol-core.h"
  18. namespace exo {
  19. namespace wayland {
  20. WaylandDisplayHandler::WaylandDisplayHandler(WaylandDisplayOutput* output,
  21. wl_resource* output_resource)
  22. : output_(output), output_resource_(output_resource) {
  23. }
  24. WaylandDisplayHandler::~WaylandDisplayHandler() {
  25. for (auto& obs : observers_)
  26. obs.OnOutputDestroyed();
  27. if (xdg_output_resource_)
  28. wl_resource_set_user_data(xdg_output_resource_, nullptr);
  29. output_->UnregisterOutput(output_resource_);
  30. }
  31. void WaylandDisplayHandler::Initialize() {
  32. // Adding itself as an observer will send the initial display metrics.
  33. AddObserver(this);
  34. output_->RegisterOutput(output_resource_);
  35. }
  36. void WaylandDisplayHandler::AddObserver(WaylandDisplayObserver* observer) {
  37. observers_.AddObserver(observer);
  38. display::Display display;
  39. bool exists = display::Screen::GetScreen()->GetDisplayWithDisplayId(
  40. output_->id(), &display);
  41. if (!exists) {
  42. // WaylandDisplayHandler is created asynchronously, and the
  43. // display can be deleted before created. This usually won't happen
  44. // in real environment, but can happen in test environment.
  45. return;
  46. }
  47. // Send the first round of changes to the observer.
  48. constexpr uint32_t all_changes = 0xFFFFFFFF;
  49. if (observer->SendDisplayMetrics(display, all_changes)) {
  50. if (wl_resource_get_version(output_resource_) >=
  51. WL_OUTPUT_DONE_SINCE_VERSION) {
  52. wl_output_send_done(output_resource_);
  53. }
  54. wl_client_flush(wl_resource_get_client(output_resource_));
  55. }
  56. }
  57. void WaylandDisplayHandler::RemoveObserver(WaylandDisplayObserver* observer) {
  58. observers_.RemoveObserver(observer);
  59. }
  60. int64_t WaylandDisplayHandler::id() const {
  61. DCHECK(output_);
  62. return output_->id();
  63. }
  64. void WaylandDisplayHandler::OnDisplayMetricsChanged(
  65. const display::Display& display,
  66. uint32_t changed_metrics) {
  67. DCHECK(output_resource_);
  68. if (output_->id() != display.id())
  69. return;
  70. bool needs_done = false;
  71. for (auto& observer : observers_)
  72. needs_done |= observer.SendDisplayMetrics(display, changed_metrics);
  73. if (needs_done) {
  74. if (wl_resource_get_version(output_resource_) >=
  75. WL_OUTPUT_DONE_SINCE_VERSION) {
  76. wl_output_send_done(output_resource_);
  77. }
  78. wl_client_flush(wl_resource_get_client(output_resource_));
  79. }
  80. }
  81. void WaylandDisplayHandler::OnXdgOutputCreated(
  82. wl_resource* xdg_output_resource) {
  83. DCHECK(!xdg_output_resource_);
  84. xdg_output_resource_ = xdg_output_resource;
  85. display::Display display;
  86. if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(output_->id(),
  87. &display)) {
  88. return;
  89. }
  90. OnDisplayMetricsChanged(display, 0xFFFFFFFF);
  91. }
  92. void WaylandDisplayHandler::UnsetXdgOutputResource() {
  93. DCHECK(xdg_output_resource_);
  94. xdg_output_resource_ = nullptr;
  95. }
  96. void WaylandDisplayHandler::XdgOutputSendLogicalPosition(
  97. const gfx::Point& position) {
  98. zxdg_output_v1_send_logical_position(xdg_output_resource_, position.x(),
  99. position.y());
  100. }
  101. void WaylandDisplayHandler::XdgOutputSendLogicalSize(const gfx::Size& size) {
  102. zxdg_output_v1_send_logical_size(xdg_output_resource_, size.width(),
  103. size.height());
  104. }
  105. void WaylandDisplayHandler::XdgOutputSendDescription(const std::string& desc) {
  106. zxdg_output_v1_send_description(xdg_output_resource_, desc.c_str());
  107. }
  108. bool WaylandDisplayHandler::SendDisplayMetrics(const display::Display& display,
  109. uint32_t changed_metrics) {
  110. if (!output_resource_)
  111. return false;
  112. // There is no need to check DISPLAY_METRIC_PRIMARY because when primary
  113. // changes, bounds always changes. (new primary should have had non
  114. // 0,0 origin).
  115. // Only exception is when switching to newly connected primary with
  116. // the same bounds. This happens whenyou're in docked mode, suspend,
  117. // unplug the display, then resume to the internal display which has
  118. // the same resolution. Since metrics does not change, there is no need
  119. // to notify clients.
  120. if (!(changed_metrics &
  121. (DISPLAY_METRIC_BOUNDS | DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
  122. DISPLAY_METRIC_ROTATION))) {
  123. return false;
  124. }
  125. const display::ManagedDisplayInfo& info =
  126. WMHelper::GetInstance()->GetDisplayInfo(display.id());
  127. const float kInchInMm = 25.4f;
  128. const char* kUnknown = "unknown";
  129. const std::string& make = info.manufacturer_id();
  130. const std::string& model = info.product_id();
  131. // TODO(oshima): The current Wayland protocol currently has no way of
  132. // informing a client about any overscan the display has, and what the safe
  133. // area of the display might be. We may want to make a change to the
  134. // aura-shell (zaura_output) protocol, or to upstream a change to the
  135. // xdg-output (currently unstable) protocol to add that information.
  136. // |origin| is used in wayland service to identify the workspace
  137. // the pixel size will be applied.
  138. const gfx::Point origin = display.bounds().origin();
  139. // |physical_size_px| is the physical resolution of the display in pixels.
  140. // The value should not include any overscan insets or display rotation,
  141. // except for any panel orientation adjustment.
  142. const gfx::Size physical_size_px = info.bounds_in_native().size();
  143. // |physical_size_mm| is our best-effort approximation for the physical size
  144. // of the display in millimeters, given the display resolution and DPI. The
  145. // value should not include any overscan insets or display rotation, except
  146. // for any panel orientation adjustment.
  147. const gfx::Size physical_size_mm =
  148. ScaleToRoundedSize(physical_size_px, kInchInMm / info.device_dpi());
  149. // Use panel_rotation otherwise some X apps will refuse to take events from
  150. // outside the "visible" region.
  151. wl_output_send_geometry(output_resource_, origin.x(), origin.y(),
  152. physical_size_mm.width(), physical_size_mm.height(),
  153. WL_OUTPUT_SUBPIXEL_UNKNOWN,
  154. make.empty() ? kUnknown : make.c_str(),
  155. model.empty() ? kUnknown : model.c_str(),
  156. OutputTransform(display.panel_rotation()));
  157. // TODO(reveman): Send real list of modes.
  158. wl_output_send_mode(output_resource_,
  159. WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED,
  160. physical_size_px.width(), physical_size_px.height(),
  161. static_cast<int>(60000));
  162. if (xdg_output_resource_) {
  163. XdgOutputSendLogicalPosition(origin);
  164. XdgOutputSendLogicalSize(display.bounds().size());
  165. XdgOutputSendDescription(display.label());
  166. } else {
  167. if (wl_resource_get_version(output_resource_) >=
  168. WL_OUTPUT_SCALE_SINCE_VERSION) {
  169. // wl_output only supports integer scaling, so if device scale factor is
  170. // fractional we need to round it up to the closest integer.
  171. wl_output_send_scale(output_resource_,
  172. std::ceil(display.device_scale_factor()));
  173. }
  174. }
  175. return true;
  176. }
  177. void WaylandDisplayHandler::OnOutputDestroyed() {
  178. // destroying itself.
  179. RemoveObserver(this);
  180. }
  181. size_t WaylandDisplayHandler::CountObserversForTesting() const {
  182. size_t count = 0;
  183. for (auto& obs : observers_) {
  184. if (&obs != this)
  185. count++;
  186. }
  187. return count;
  188. }
  189. } // namespace wayland
  190. } // namespace exo