1 // Copyright 2013 Intel Corporation. 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.
5 #include "ozone/impl/ozone_display.h"
8 #include "content/child/child_process.h"
9 #include "ozone/impl/desktop_screen_wayland.h"
10 #include "ozone/impl/ipc/display_channel.h"
11 #include "ozone/impl/ipc/display_channel_host.h"
12 #include "ozone/ui/events/event_converter_in_process.h"
13 #include "ozone/ui/events/remote_event_dispatcher.h"
14 #include "ozone/wayland/display.h"
15 #include "ozone/wayland/screen.h"
16 #include "ozone/wayland/window.h"
18 namespace ozonewayland {
20 OzoneDisplay* OzoneDisplay::instance_ = NULL;
21 const int kMaxDisplaySize = 20;
23 OzoneDisplay* OzoneDisplay::GetInstance() {
27 OzoneDisplay::OzoneDisplay() : desktop_screen_(NULL),
31 event_converter_(NULL),
36 OzoneDisplay::~OzoneDisplay() {
41 const char* OzoneDisplay::DefaultDisplaySpec() {
43 spec_ = new char[kMaxDisplaySize];
44 if (desktop_screen_ && !desktop_screen_->geometry().size().IsEmpty()) {
45 gfx::Rect rect(desktop_screen_->geometry());
58 "OutputHandleMode should come from Wayland compositor first";
63 bool OzoneDisplay::InitializeHardware() {
64 display_ = new WaylandDisplay(WaylandDisplay::RegisterAsNeeded);
65 bool initialized_hardware = display_->display() ? true : false;
66 if (initialized_hardware && !content::ChildProcess::current()) {
67 // In the multi-process mode, DisplayChannel (in GPU process side) is in
68 // charge of establishing an IPC channel with DisplayChannelHost (in
69 // Browser Process side). At this moment the GPU process is still
70 // initializing though, so DisplayChannel cannot establish the connection
71 // and need to delay this to later. Therefore post a task to GpuChildThread
72 // and let DisplayChannel handle this right after the GPU process is
74 base::MessageLoop::current()->message_loop_proxy()->PostTask(
75 FROM_HERE, base::Bind(&OzoneDisplay::DelayedInitialization, this));
78 return initialized_hardware;
81 void OzoneDisplay::ShutdownHardware() {
85 intptr_t OzoneDisplay::GetNativeDisplay() {
86 return (intptr_t)display_->display();
89 gfx::Screen* OzoneDisplay::CreateDesktopScreen() {
90 if (!desktop_screen_) {
91 desktop_screen_ = new views::DesktopScreenWayland;
92 LookAheadOutputGeometry();
95 return desktop_screen_;
98 const views::DesktopScreenWayland* OzoneDisplay::GetPrimaryScreen() const {
99 // TODO(kalyan): For now always return DesktopScreen. Needs proper fixing
100 // after multi screen support is added.
101 return desktop_screen_;
104 gfx::AcceleratedWidget OzoneDisplay::GetAcceleratedWidget() {
105 static int opaque_handle = 0;
106 // Ensure Event Converter is initialized.
107 if (!event_converter_) {
108 event_converter_ = new EventConverterInProcess();
109 event_converter_->SetOutputChangeObserver(this);
112 display_->StartProcessingEvents();
115 host_ = new OzoneDisplayChannelHost();
120 WindowStateChangeHandler::GetInstance()->SetWidgetState(opaque_handle,
125 return (gfx::AcceleratedWidget)opaque_handle;
128 gfx::AcceleratedWidget OzoneDisplay::RealizeAcceleratedWidget(
129 gfx::AcceleratedWidget w) {
131 // Event Converter should be already initialized unless we are in gpu process
133 if (!event_converter_) {
134 event_converter_ = new RemoteEventDispatcher();
135 display_->StartProcessingEvents();
138 WaylandWindow* widget = GetWidget(w);
140 widget->RealizeAcceleratedWidget();
141 return (gfx::AcceleratedWidget)widget->egl_window();
144 void OzoneDisplay::OnOutputSizeChanged(unsigned width, unsigned height) {
146 base::snprintf(spec_, kMaxDisplaySize, "%dx%d*2", width, height);
148 desktop_screen_->SetGeometry(gfx::Rect(0, 0, width, height));
151 void OzoneDisplay::DelayedInitialization(OzoneDisplay* display) {
152 display->channel_ = new OzoneDisplayChannel();
153 display->channel_->Register();
156 WaylandWindow* OzoneDisplay::GetWidget(gfx::AcceleratedWidget w) {
157 const std::map<unsigned, WaylandWindow*> widget_map =
158 display_->GetWindowList();
160 std::map<unsigned, WaylandWindow*>::const_iterator it = widget_map.find(w);
161 return it == widget_map.end() ? NULL : it->second;
164 void OzoneDisplay::Terminate() {
165 if (!event_converter_ && !desktop_screen_)
172 if (desktop_screen_) {
173 delete desktop_screen_;
174 desktop_screen_ = NULL;
178 if (event_converter_) {
179 delete event_converter_;
180 event_converter_ = NULL;
184 // TODO(vignatti): GPU process conceptually is the one that deals with hardware
185 // details and therefore we assume that the window system connection should
186 // happen in there only. There's a glitch with Chrome though, that creates its
187 // frame contents requiring access to the window system, before the GPU process
188 // even exists. In other words, Chrome runs
189 // BrowserMainLoop::PreMainMessageLoopRun before GpuProcessHost::Get. If the
190 // assumption of window system connection belongs to the GPU process is valid,
191 // then I believe this Chrome behavior needs to be addressed upstream.
193 // For now, we create another window system connection to look ahead the needed
194 // output properties that Chrome (among others) need and then close right after
195 // that. I haven't measured how long it takes to open a Wayland connection,
196 // listen all the interface the compositor sends and close it, but _for_ _sure_
197 // it slows down the overall initialization time of Chromium targets.
198 // Therefore, this is something that has to be solved in the future, moving all
199 // Chrome tasks after GPU process is created.
201 void OzoneDisplay::LookAheadOutputGeometry() {
202 DCHECK(desktop_screen_);
203 WaylandDisplay disp_(WaylandDisplay::RegisterOutputOnly);
204 CHECK(disp_.display()) << "Ozone: Wayland server connection not found.";
206 while (disp_.PrimaryScreen()->Geometry().IsEmpty())
209 desktop_screen_->SetGeometry(disp_.PrimaryScreen()->Geometry());
212 } // namespace ozonewayland