Commit 015f3ed1 authored by Antonio Gomes's avatar Antonio Gomes Committed by Santosh Mahto

Allow ws to pass display::Display data to Aura/client

Change ScreenManagerOzoneExternal to be able to send out display::Display
updates via ws::UserDisplayManager (which will send the display::Display
to the client).

For this, patch extends OzonePlatform with a method that allows
its instances (X11, Wayland, etc) to query the host system its displays
data (resolution only for now).
ScreenManagerOzoneExternal then calls to ws::DisplayManager, which calls to

In order to allow ws::DisplayManager to get display::Display and not change
ws::Display in external mode, a new hook was added: ::OnHostDisplaysReady.

Wayland support will come in a fixup.

Issue #43

  Contains fixup in ozone_platform_headless for fixing

(TEMP) fixup! Allow ws to pass display::Display data to Aura/client

  Fix creating ui::Display after
  is upstreamed

fixup! Allow ws to pass display::Display data to Aura/client

Use a non-zero value for FrameDecorationValues::normal_client_area_insets,
so that the tabstrip has room to get drawn.

The value '33' was picked up by mimic'ing ChromeOS's Chrome/Mash.

Issue #56
Issue #43

fixup! Allow ws to pass display::Display data to Aura/client

PR #50, reverted an initial hack added as part of the commit
"Allow chrome launch with --mus parameter", but it left over one

This commits removes the left over bit, but in the next rebase
this should be squashed against "Allow chrome launch with --mus parameter"
commit, not "Allow ws to pass display::Display data to Aura/client".

fixup! Allow ws to pass display::Display data to Aura/client

null-check the pointer before dereferencing it. nullptr is
deliberately pass in sometimes.

Issue #43

fixup! fixup! Allow ws to pass display::Display data to Aura/client

During the April/24 rebase, msisov@ hardcoded the ScreenManager creating
in ws::service. This method adds a call to ws::Service::OnWillCreateTreeForWindowManager,
similarly to how internal window mode does.

fixup! Allow ws to pass display::Display data to Aura/client

Implement OzonePlatformWayland::QueryHostDisplaysData. Note
that by the time WaylandOutput is instantiated, the associated
WaylandConnection object needs to be able to receive and process
events, so that it can handle wl_output_listener hooks.

Issue #43

fixup! Allow ws to pass display::Display data to Aura/client

Now that Mus runs as a thread within the Browser process, we can not
install ScreenManagerOzoneExternal's Screen instance. Instead, it is
only used internally to track displays (add, remove, modify).

This fixes a crash at shutdown.

PR #250

fixup! Allow ws to pass display::Display data to Aura/client

Stop early listen to events, when wl_output is installed.
This call was causing us to enter the event loop earlier than we should,
and occasional hangs at start up.

Instead, when display/screen data is queried, we "ask" the server
to close all pending requests associated with a given wl_display.
Screen dimensions then can be queried.

Issue #212

fixup! Allow ws to pass display::Display data to Aura/client

Fix unittests: after the change to WaylandConnection::Initialize, the
unittests started to hang on startup, because the WaylandOutput::Geometry
had always been empty.

The fix is to create a MockOutput, which is a global wl object on the
server side, with non-empty geometry, which will be set during initializtion

The second fix is to modify WaylandConnectionTest::Output in such a way that
it would not wait in a blocking run loop. At the moment, we have
a wl_display_roundtrip run until WaylandOutput::Geometry is set instead.
parent 782c6704
......@@ -7,6 +7,8 @@
#include <stdint.h>
#include "services/ui/ws/user_id.h"
namespace display {
class Display;
......@@ -30,6 +32,10 @@ class ScreenManagerDelegate {
// Called when the primary display is changed.
virtual void OnPrimaryDisplayChanged(int64_t primary_display_id) = 0;
// In external window mode, query the host system about data (resolution)
// of the displays available.
virtual void OnHostDisplaysReady(const ui::ws::UserId& user_id) = 0;
virtual ~ScreenManagerDelegate() {}
......@@ -7,8 +7,10 @@
#include <memory>
#include "services/service_manager/public/cpp/binder_registry.h"
#include "ui/display/screen_base.h"
#include "services/service_manager/public/interfaces/connector.mojom.h"
#include "ui/display/types/display_constants.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/ozone/public/ozone_platform.h"
namespace display {
......@@ -18,15 +20,44 @@ std::unique_ptr<ScreenManager> ScreenManager::Create() {
: screen_(base::MakeUnique<display::ScreenBase>()) {}
: screen_(base::MakeUnique<ScreenBase>()),
weak_ptr_factory_(this) {
ScreenManagerOzoneExternal::~ScreenManagerOzoneExternal() {}
void ScreenManagerOzoneExternal::OnHostDisplaysReady(
const std::vector<gfx::Size>& dimensions) {
float device_scale_factor = 1.f;
if (Display::HasForceDeviceScaleFactor())
device_scale_factor = Display::GetForcedDeviceScaleFactor();
gfx::Size scaled_size =
gfx::ConvertSizeToDIP(device_scale_factor, dimensions[0]);
Display display(next_display_id_++);
screen_->display_list().AddDisplay(display, DisplayList::Type::PRIMARY);
// TODO(tonikitoo, msisov): Before calling out to ScreenManagerDelegate check if
// more than one host display is available.
void ScreenManagerOzoneExternal::AddInterfaces(
const service_manager::BindSourceInfo&>* registry) {}
void ScreenManagerOzoneExternal::Init(ScreenManagerDelegate* delegate) {}
void ScreenManagerOzoneExternal::Init(ScreenManagerDelegate* delegate) {
delegate_ = delegate;
void ScreenManagerOzoneExternal::RequestCloseDisplay(int64_t display_id) {}
......@@ -7,6 +7,9 @@
#include "services/ui/display/screen_manager.h"
#include "base/memory/weak_ptr.h"
#include "ui/display/screen_base.h"
namespace display {
// In external window mode, the purpose of having a ScreenManager
......@@ -22,6 +25,10 @@ class ScreenManagerOzoneExternal : public ScreenManager {
~ScreenManagerOzoneExternal() override;
// Callback to be called from the Ozone platform when
// host displays' data are ready.
void OnHostDisplaysReady(const std::vector<gfx::Size>&);
// ScreenManager.
void AddInterfaces(
......@@ -30,7 +37,14 @@ class ScreenManagerOzoneExternal : public ScreenManager {
void RequestCloseDisplay(int64_t display_id) override;
display::ScreenBase* GetScreen() override;
std::unique_ptr<display::ScreenBase> screen_;
// Internal control for displays added/removed/modified.
// THIS IS NOT INSTALLED IN Screen::SetScreenInstancce.
std::unique_ptr<ScreenBase> screen_;
ScreenManagerDelegate* delegate_ = nullptr;
int next_display_id_ = 0;
base::WeakPtrFactory<ScreenManagerOzoneExternal> weak_ptr_factory_;
......@@ -105,6 +105,8 @@ class TestScreenManagerDelegate : public ScreenManagerDelegate {
AddChange("Primary", base::Int64ToString(primary_display_id));
void OnHostDisplaysReady(const ui::ws::UserId& user_id) override {}
std::vector<DisplayState> added_;
std::vector<DisplayState> modified_;
std::string changes_;
......@@ -442,8 +442,9 @@ void Service::BindClipboardRequest(
void Service::BindDisplayManagerRequest(
mojom::DisplayManagerRequest request,
const service_manager::BindSourceInfo& source_info) {
// Wait for the DisplayManager to be configured before binding display
// requests. Otherwise the client sees no displays.
// DisplayManagerObservers generally expect there to be at least one
// ws::display, except on LinuxOS/Ozone (external window mode).
#if !defined(USE_OZONE) || defined(OS_CHROMEOS)
if (!window_server_->display_manager()->IsReady()) {
std::unique_ptr<PendingRequest> pending_request(new PendingRequest);
pending_request->source_info = source_info;
......@@ -452,6 +453,7 @@ void Service::BindDisplayManagerRequest(
......@@ -416,5 +416,12 @@ void DisplayManager::OnPrimaryDisplayChanged(int64_t primary_display_id) {
void DisplayManager::OnHostDisplaysReady(const UserId& user_id) {
// Valid only for when in external window mode.
// For now, mimic the behavior of whether we had received the
// frame decoration data from the Window Manager.
} // namespace ws
} // namespace ui
......@@ -134,6 +134,7 @@ class DisplayManager : public UserIdTrackerObserver,
void OnDisplayModified(const display::Display& display,
const display::ViewportMetrics& metrics) override;
void OnPrimaryDisplayChanged(int64_t primary_display_id) override;
void OnHostDisplaysReady(const UserId& user_id) override;
WindowServer* window_server_;
UserIdTracker* user_id_tracker_;
......@@ -626,6 +626,17 @@ void WindowServer::OnFirstSurfaceActivation(
bool WindowServer::GetFrameDecorationsForUser(
const UserId& user_id,
mojom::FrameDecorationValuesPtr* values) {
if (IsInExternalWindowMode() && values) {
*values = mojom::FrameDecorationValues::New();
// '33' was picked up by trial/error and because this is the value
// used in ChromeOS/mash builds. The value is used to calculate chrome's
// tabstrip height in BrowserNonClientFrameViewMus::GetHeaderHeigh().
// TODO(tonikitoo,msisov): Maybe there is some refinement to be done here?
// What about maximized_client_area_insets and max_title_bar_button_width?
(*values)->normal_client_area_insets = gfx::Insets(33, 0, 0, 0);
return true;
WindowManagerState* window_manager_state =
......@@ -97,6 +97,13 @@ class OzonePlatformHeadless : public OzonePlatform {
surface_factory_ = std::make_unique<HeadlessSurfaceFactory>(file_path_);
void QueryHostDisplaysData(QueryHostDisplaysDataCallback callback) override {
// For now just use a random resolution so that unit tests pass.
callback.Run(std::vector<gfx::Size>(1, gfx::Size(1024, 768)));
std::unique_ptr<HeadlessWindowManager> window_manager_;
std::unique_ptr<HeadlessSurfaceFactory> surface_factory_;
......@@ -437,7 +437,8 @@ void MockCompositor::AddSurface(std::unique_ptr<MockSurface> surface) {
: Global(&wl_output_interface, nullptr, kOutputVersion) {}
: Global(&wl_output_interface, nullptr, kOutputVersion),
rect_(0, 0, 1024, 768) {}
MockOutput::~MockOutput() {}
......@@ -74,6 +74,19 @@ class OzonePlatformWayland : public OzonePlatform {
return std::make_unique<display::FakeDisplayDelegate>();
void QueryHostDisplaysData(QueryHostDisplaysDataCallback callback) override {
// On Wayland, the screen dimensions come from WaylandOutput.
if (connection_->PrimaryOutput()) {
gfx::Rect geometry = connection_->PrimaryOutput()->Geometry();
callback.Run(std::vector<gfx::Size>(1, geometry.size()));
CHECK(false) << "Add support for asynchronous resolution fetch.";
void InitializeUI(const InitParams& args) override {
connection_.reset(new WaylandConnection);
if (!connection_->Initialize())
......@@ -48,7 +48,9 @@ bool WaylandConnection::Initialize() {
wl_registry_add_listener(registry_.get(), &registry_listener, this);
while (!PrimaryOutput() || PrimaryOutput()->Geometry().IsEmpty())
if (!compositor_) {
LOG(ERROR) << "No wl_compositor object";
......@@ -73,10 +73,16 @@ TEST(WaylandConnectionTest, Output) {
base::RunLoop run_loop;
OutputObserver observer(run_loop.QuitClosure());
/* Before adding a waiting loop to WaylandConnection::Initilize,
* this setting of the observer worked. But as long as we now wait
* until all the events are processed and the output handle mode is set,
* it's too late to add an observer at this point.
* base::RunLoop run_loop;
* OutputObserver observer(run_loop.QuitClosure());
* connection.PrimaryOutput()->SetObserver(&observer);
* run_loop.Run();
ASSERT_TRUE(connection.GetOutputList().size() == 1);
WaylandOutput* output = connection.PrimaryOutput();
......@@ -101,6 +101,16 @@ class OzonePlatformX11 : public OzonePlatform {
surface_factory_ozone_ = std::make_unique<X11SurfaceFactory>();
void QueryHostDisplaysData(QueryHostDisplaysDataCallback callback) override {
// TODO(tonikitoo): Add support to multiple displays.
XDisplay* display = gfx::GetXDisplay();
Screen* screen = DefaultScreenOfDisplay(display);
std::vector<gfx::Size>(1, gfx::Size(screen->width, screen->height)));
base::MessageLoop::Type GetMessageLoopTypeForGpu() override {
// When Ozone X11 backend is running use an UI loop to grab Expose events.
// See GLSurfaceGLX and
......@@ -90,6 +90,11 @@ base::MessageLoop::Type OzonePlatform::GetMessageLoopTypeForGpu() {
return base::MessageLoop::TYPE_DEFAULT;
void OzonePlatform::QueryHostDisplaysData(
QueryHostDisplaysDataCallback callback) {
void OzonePlatform::AddInterfaces(
const service_manager::BindSourceInfo&>* registry) {}
......@@ -7,11 +7,13 @@
#include <memory>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "ui/events/system_input_injector.h"
#include "ui/gfx/geometry/size.h"
#include "ui/ozone/ozone_export.h"
namespace display {
......@@ -112,6 +114,10 @@ class OZONE_EXPORT OzonePlatform {
virtual std::unique_ptr<display::NativeDisplayDelegate>
CreateNativeDisplayDelegate() = 0;
using QueryHostDisplaysDataCallback =
base::Callback<void(const std::vector<gfx::Size>&)>;
virtual void QueryHostDisplaysData(QueryHostDisplaysDataCallback callback);
// Returns the message loop type required for OzonePlatform instance that
// will be initialized for the GPU process.
virtual base::MessageLoop::Type GetMessageLoopTypeForGpu();
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment