140076fd88b2bfa551379044cef9977f71b74ff2
[platform/framework/web/crosswalk.git] / src / ozone / impl / ozone_display.cc
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.
4
5 #include "ozone/impl/ozone_display.h"
6
7 #include <map>
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"
17
18 namespace ozonewayland {
19
20 OzoneDisplay* OzoneDisplay::instance_ = NULL;
21 const int kMaxDisplaySize = 20;
22
23 OzoneDisplay* OzoneDisplay::GetInstance() {
24   return instance_;
25 }
26
27 OzoneDisplay::OzoneDisplay() : desktop_screen_(NULL),
28     display_(NULL),
29     channel_(NULL),
30     host_(NULL),
31     event_converter_(NULL),
32     spec_(NULL) {
33   instance_ = this;
34 }
35
36 OzoneDisplay::~OzoneDisplay() {
37   Terminate();
38   instance_ = NULL;
39 }
40
41 const char* OzoneDisplay::DefaultDisplaySpec() {
42   if (!spec_) {
43     spec_ = new char[kMaxDisplaySize];
44     if (desktop_screen_ && !desktop_screen_->geometry().size().IsEmpty())  {
45       gfx::Rect rect(desktop_screen_->geometry());
46       base::snprintf(spec_,
47                      kMaxDisplaySize,
48                      "%dx%d*2",
49                      rect.width(),
50                      rect.height());
51     } else {
52       spec_[0] = '\0';
53     }
54   }
55
56   if (spec_[0] == '\0')
57     NOTREACHED() <<
58         "OutputHandleMode should come from Wayland compositor first";
59
60   return spec_;
61 }
62
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
73     // initialized.
74     base::MessageLoop::current()->message_loop_proxy()->PostTask(
75         FROM_HERE, base::Bind(&OzoneDisplay::DelayedInitialization, this));
76   }
77
78   return initialized_hardware;
79 }
80
81 void OzoneDisplay::ShutdownHardware() {
82   Terminate();
83 }
84
85 intptr_t OzoneDisplay::GetNativeDisplay() {
86   return (intptr_t)display_->display();
87 }
88
89 gfx::Screen* OzoneDisplay::CreateDesktopScreen() {
90   if (!desktop_screen_) {
91     desktop_screen_ = new views::DesktopScreenWayland;
92     LookAheadOutputGeometry();
93   }
94
95   return desktop_screen_;
96 }
97
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_;
102 }
103
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);
110
111     if (display_) {
112       display_->StartProcessingEvents();
113     } else {
114       DCHECK(!host_);
115       host_ = new OzoneDisplayChannelHost();
116     }
117   }
118
119   opaque_handle++;
120   WindowStateChangeHandler::GetInstance()->SetWidgetState(opaque_handle,
121                                                           CREATE,
122                                                           0,
123                                                           0);
124
125   return (gfx::AcceleratedWidget)opaque_handle;
126 }
127
128 gfx::AcceleratedWidget OzoneDisplay::RealizeAcceleratedWidget(
129     gfx::AcceleratedWidget w) {
130   DCHECK(display_);
131   // Event Converter should be already initialized unless we are in gpu process
132   // side.
133   if (!event_converter_) {
134     event_converter_ = new RemoteEventDispatcher();
135     display_->StartProcessingEvents();
136   }
137
138   WaylandWindow* widget = GetWidget(w);
139   DCHECK(widget);
140   widget->RealizeAcceleratedWidget();
141   return (gfx::AcceleratedWidget)widget->egl_window();
142 }
143
144 void OzoneDisplay::OnOutputSizeChanged(unsigned width, unsigned height) {
145   if (spec_)
146     base::snprintf(spec_, kMaxDisplaySize, "%dx%d*2", width, height);
147   if (desktop_screen_)
148     desktop_screen_->SetGeometry(gfx::Rect(0, 0, width, height));
149 }
150
151 void OzoneDisplay::DelayedInitialization(OzoneDisplay* display) {
152   display->channel_ = new OzoneDisplayChannel();
153   display->channel_->Register();
154 }
155
156 WaylandWindow* OzoneDisplay::GetWidget(gfx::AcceleratedWidget w) {
157   const std::map<unsigned, WaylandWindow*> widget_map =
158       display_->GetWindowList();
159
160   std::map<unsigned, WaylandWindow*>::const_iterator it = widget_map.find(w);
161     return it == widget_map.end() ? NULL : it->second;
162 }
163
164 void OzoneDisplay::Terminate() {
165   if (!event_converter_ && !desktop_screen_)
166     return;
167
168   if (spec_)
169     delete[] spec_;
170
171   delete channel_;
172   if (desktop_screen_) {
173     delete desktop_screen_;
174     desktop_screen_ = NULL;
175   }
176
177   delete display_;
178   if (event_converter_) {
179     delete event_converter_;
180     event_converter_ = NULL;
181   }
182 }
183
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.
192 //
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.
200 //
201 void OzoneDisplay::LookAheadOutputGeometry() {
202   DCHECK(desktop_screen_);
203   WaylandDisplay disp_(WaylandDisplay::RegisterOutputOnly);
204   CHECK(disp_.display()) << "Ozone: Wayland server connection not found.";
205
206   while (disp_.PrimaryScreen()->Geometry().IsEmpty())
207     disp_.SyncDisplay();
208
209   desktop_screen_->SetGeometry(disp_.PrimaryScreen()->Geometry());
210 }
211
212 }  // namespace ozonewayland