Upstream version 11.39.252.0
[platform/framework/web/crosswalk.git] / src / ozone / wayland / display.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Copyright 2013 Intel Corporation. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "ozone/wayland/display.h"
7
8 #include <EGL/egl.h>
9 #include <string>
10
11 #include "base/files/file_path.h"
12 #include "base/native_library.h"
13 #include "base/stl_util.h"
14 #include "ozone/ui/events/event_factory_ozone_wayland.h"
15 #include "ozone/ui/events/output_change_observer.h"
16 #include "ozone/wayland/display_poll_thread.h"
17 #include "ozone/wayland/egl/surface_ozone_wayland.h"
18 #include "ozone/wayland/input/cursor.h"
19 #include "ozone/wayland/input_device.h"
20 #include "ozone/wayland/screen.h"
21 #include "ozone/wayland/shell/shell.h"
22 #include "ozone/wayland/window.h"
23
24 namespace ozonewayland {
25 WaylandDisplay* WaylandDisplay::instance_ = NULL;
26
27 WaylandDisplay::WaylandDisplay() : SurfaceFactoryOzone(),
28     display_(NULL),
29     registry_(NULL),
30     compositor_(NULL),
31     shell_(NULL),
32     shm_(NULL),
33     primary_screen_(NULL),
34     look_ahead_screen_(NULL),
35     primary_input_(NULL),
36     display_poll_thread_(NULL),
37     screen_list_(),
38     input_list_(),
39     widget_map_(),
40     serial_(0),
41     processing_events_(false) {
42 }
43
44 WaylandDisplay::~WaylandDisplay() {
45   Terminate();
46 }
47
48 const std::list<WaylandScreen*>& WaylandDisplay::GetScreenList() const {
49   return screen_list_;
50 }
51
52 WaylandWindow* WaylandDisplay::GetWindow(unsigned window_handle) const {
53   return GetWidget(window_handle);
54 }
55
56 struct wl_text_input_manager* WaylandDisplay::GetTextInputManager() const {
57   return text_input_manager_;
58 }
59
60 void WaylandDisplay::FlushDisplay() {
61   wl_display_flush(display_);
62 }
63
64 void WaylandDisplay::DestroyWindow(unsigned w) {
65   std::map<unsigned, WaylandWindow*>::const_iterator it = widget_map_.find(w);
66   WaylandWindow* widget = it == widget_map_.end() ? NULL : it->second;
67   DCHECK(widget);
68   delete widget;
69   widget_map_.erase(w);
70   if (widget_map_.empty())
71     StopProcessingEvents();
72 }
73
74 gfx::AcceleratedWidget WaylandDisplay::GetNativeWindow(unsigned window_handle) {
75   // Ensure we are processing wayland event requests.
76   StartProcessingEvents();
77   WaylandWindow* widget = GetWidget(window_handle);
78   DCHECK(widget);
79   widget->RealizeAcceleratedWidget();
80
81   return (gfx::AcceleratedWidget)widget->egl_window();
82 }
83
84 bool WaylandDisplay::InitializeHardware() {
85   InitializeDisplay();
86   if (!display_) {
87     LOG(ERROR) << "WaylandDisplay failed to initialize hardware";
88     return false;
89   }
90
91   return true;
92 }
93
94 intptr_t WaylandDisplay::GetNativeDisplay() {
95   return (intptr_t)display_;
96 }
97
98 scoped_ptr<ui::SurfaceOzoneEGL> WaylandDisplay::CreateEGLSurfaceForWidget(
99     gfx::AcceleratedWidget w) {
100   return make_scoped_ptr<ui::SurfaceOzoneEGL>(new SurfaceOzoneWayland(w));
101 }
102
103 bool WaylandDisplay::LoadEGLGLES2Bindings(
104     ui::SurfaceFactoryOzone::AddGLLibraryCallback add_gl_library,
105     ui::SurfaceFactoryOzone::SetGLGetProcAddressProcCallback setprocaddress) {
106   // The variable EGL_PLATFORM specifies native platform to be used by the
107   // drivers (atleast on Mesa). When the variable is not set, Mesa uses the
108   // first platform listed in --with-egl-platforms during compilation. Thus, we
109   // ensure here that wayland is set as the native platform. However, we don't
110   // override the EGL_PLATFORM value in case it has already been set.
111   setenv("EGL_PLATFORM", "wayland", 0);
112   base::NativeLibraryLoadError error;
113   base::NativeLibrary gles_library = base::LoadNativeLibrary(
114     base::FilePath("libGLESv2.so.2"), &error);
115
116   if (!gles_library) {
117     LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
118     return false;
119   }
120
121   base::NativeLibrary egl_library = base::LoadNativeLibrary(
122     base::FilePath("libEGL.so.1"), &error);
123
124   if (!egl_library) {
125     LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
126     base::UnloadNativeLibrary(gles_library);
127     return false;
128   }
129
130   GLGetProcAddressProc get_proc_address =
131       reinterpret_cast<GLGetProcAddressProc>(
132           base::GetFunctionPointerFromNativeLibrary(
133               egl_library, "eglGetProcAddress"));
134
135   if (!get_proc_address) {
136     LOG(ERROR) << "eglGetProcAddress not found.";
137     base::UnloadNativeLibrary(egl_library);
138     base::UnloadNativeLibrary(gles_library);
139     return false;
140   }
141
142   setprocaddress.Run(get_proc_address);
143   add_gl_library.Run(egl_library);
144   add_gl_library.Run(gles_library);
145   return true;
146 }
147
148 const int32*
149 WaylandDisplay::GetEGLSurfaceProperties(const int32* desired_list) {
150   static const EGLint kConfigAttribs[] = {
151     EGL_BUFFER_SIZE, 32,
152     EGL_ALPHA_SIZE, 8,
153     EGL_BLUE_SIZE, 8,
154     EGL_GREEN_SIZE, 8,
155     EGL_RED_SIZE, 8,
156     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
157     EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
158     EGL_NONE
159   };
160
161   return kConfigAttribs;
162 }
163
164 void WaylandDisplay::SetWidgetState(unsigned w,
165                                     ui::WidgetState state,
166                                     unsigned width,
167                                     unsigned height) {
168   switch (state) {
169     case ui::CREATE:
170     {
171       CreateAcceleratedSurface(w);
172       break;
173     }
174     case ui::FULLSCREEN:
175     {
176       WaylandWindow* widget = GetWidget(w);
177       widget->SetFullscreen();
178       widget->Resize(width, height);
179       break;
180     }
181     case ui::MAXIMIZED:
182     {
183       WaylandWindow* widget = GetWidget(w);
184       widget->Maximize();
185       break;
186     }
187     case ui::MINIMIZED:
188     {
189       WaylandWindow* widget = GetWidget(w);
190       widget->Minimize();
191       break;
192     }
193     case ui::RESTORE:
194     {
195       WaylandWindow* widget = GetWidget(w);
196       widget->Restore();
197       widget->Resize(width, height);
198       break;
199     }
200     case ui::ACTIVE:
201       NOTIMPLEMENTED() << " ACTIVE " << w;
202       break;
203     case ui::INACTIVE:
204       NOTIMPLEMENTED() << " INACTIVE " << w;
205       break;
206     case ui::SHOW:
207       NOTIMPLEMENTED() << " SHOW " << w;
208       break;
209     case ui::HIDE:
210       NOTIMPLEMENTED() << " HIDE " << w;
211       break;
212     default:
213       break;
214   }
215 }
216
217 void WaylandDisplay::SetWidgetTitle(unsigned w,
218                                     const base::string16& title) {
219   WaylandWindow* widget = GetWidget(w);
220   DCHECK(widget);
221   widget->SetWindowTitle(title);
222 }
223
224 void WaylandDisplay::SetWidgetCursor(int cursor_type) {
225   primary_input_->SetCursorType(cursor_type);
226 }
227
228 void WaylandDisplay::SetWidgetAttributes(unsigned widget,
229                                          unsigned parent,
230                                          unsigned x,
231                                          unsigned y,
232                                          ui::WidgetType type) {
233   WaylandWindow* window = GetWidget(widget);
234   WaylandWindow* parent_window = GetWidget(parent);
235   DCHECK(window);
236   switch (type) {
237   case ui::WINDOW:
238     window->SetShellAttributes(WaylandWindow::TOPLEVEL);
239     break;
240   case ui::WINDOWFRAMELESS:
241     NOTIMPLEMENTED();
242     break;
243   case ui::POPUP:
244     DCHECK(parent_window);
245     window->SetShellAttributes(WaylandWindow::POPUP,
246                                parent_window->ShellSurface(),
247                                x,
248                                y);
249     break;
250   default:
251     break;
252   }
253 }
254
255
256 // TODO(vignatti): GPU process conceptually is the one that deals with hardware
257 // details and therefore we assume that the window system connection should
258 // happen in there only. There's a glitch with Chrome though, that creates its
259 // frame contents requiring access to the window system, before the GPU process
260 // even exists. In other words, Chrome runs
261 // BrowserMainLoop::PreMainMessageLoopRun before GpuProcessHost::Get. If the
262 // assumption of window system connection belongs to the GPU process is valid,
263 // then I believe this Chrome behavior needs to be addressed upstream.
264 //
265 // For now, we create another window system connection to look ahead the needed
266 // output properties that Chrome (among others) need and then close right after
267 // that. I haven't measured how long it takes to open a Wayland connection,
268 // listen all the interface the compositor sends and close it, but _for_ _sure_
269 // it slows down the overall initialization time of Chromium targets.
270 // Therefore, this is something that has to be solved in the future, moving all
271 // Chrome tasks after GPU process is created.
272 //
273 void WaylandDisplay::LookAheadOutputGeometry() {
274   wl_display* display = wl_display_connect(NULL);
275   if (!display)
276     return;
277
278   static const struct wl_registry_listener registry_output = {
279     WaylandDisplay::DisplayHandleOutputOnly
280   };
281
282   wl_registry* registry = wl_display_get_registry(display);
283   wl_registry_add_listener(registry, &registry_output, this);
284
285   if (wl_display_roundtrip(display) > 0) {
286     while (look_ahead_screen_->Geometry().IsEmpty())
287       wl_display_roundtrip(display);
288
289     ui::EventFactoryOzoneWayland* event_factory =
290         ui::EventFactoryOzoneWayland::GetInstance();
291     DCHECK(event_factory->GetOutputChangeObserver());
292
293     unsigned width = look_ahead_screen_->Geometry().width();
294     unsigned height = look_ahead_screen_->Geometry().height();
295     event_factory->GetOutputChangeObserver()->OnOutputSizeChanged(width,
296                                                                   height);
297   }
298
299   if (look_ahead_screen_) {
300     delete look_ahead_screen_;
301     look_ahead_screen_ = NULL;
302   }
303
304   wl_registry_destroy(registry);
305   wl_display_flush(display);
306   wl_display_disconnect(display);
307 }
308
309 void WaylandDisplay::InitializeDisplay() {
310   DCHECK(!display_);
311   display_ = wl_display_connect(NULL);
312   if (!display_)
313     return;
314
315   instance_ = this;
316   static const struct wl_registry_listener registry_all = {
317     WaylandDisplay::DisplayHandleGlobal
318   };
319
320   registry_ = wl_display_get_registry(display_);
321   wl_registry_add_listener(registry_, &registry_all, this);
322   shell_ = new WaylandShell();
323
324   if (wl_display_roundtrip(display_) < 0) {
325     Terminate();
326     return;
327   }
328
329   ui::WindowStateChangeHandler::SetInstance(this);
330   display_poll_thread_ = new WaylandDisplayPollThread(display_);
331 }
332
333 WaylandWindow* WaylandDisplay::CreateAcceleratedSurface(unsigned w) {
334   WaylandWindow* window = new WaylandWindow(w);
335   widget_map_[w] = window;
336
337   return window;
338 }
339
340 void WaylandDisplay::StartProcessingEvents() {
341   DCHECK(display_poll_thread_);
342   // Start polling for wayland events.
343   if (!processing_events_) {
344     display_poll_thread_->StartProcessingEvents();
345     processing_events_ = true;
346   }
347 }
348
349 void WaylandDisplay::StopProcessingEvents() {
350   DCHECK(display_poll_thread_);
351   // Start polling for wayland events.
352   if (processing_events_) {
353     display_poll_thread_->StopProcessingEvents();
354     processing_events_ = false;
355   }
356 }
357
358 void WaylandDisplay::Terminate() {
359   if (!widget_map_.empty()) {
360     STLDeleteValues(&widget_map_);
361     widget_map_.clear();
362   }
363
364   for (std::list<WaylandInputDevice*>::iterator i = input_list_.begin();
365       i != input_list_.end(); ++i) {
366       delete *i;
367   }
368
369   for (std::list<WaylandScreen*>::iterator i = screen_list_.begin();
370       i != screen_list_.end(); ++i) {
371       delete *i;
372   }
373
374   screen_list_.clear();
375   input_list_.clear();
376
377   WaylandCursor::Clear();
378
379   if (compositor_)
380     wl_compositor_destroy(compositor_);
381
382   delete shell_;
383   if (shm_)
384     wl_shm_destroy(shm_);
385
386   if (registry_)
387     wl_registry_destroy(registry_);
388
389   delete display_poll_thread_;
390
391   if (display_) {
392     wl_display_flush(display_);
393     wl_display_disconnect(display_);
394     display_ = NULL;
395   }
396
397   instance_ = NULL;
398 }
399
400 WaylandWindow* WaylandDisplay::GetWidget(unsigned w) const {
401   std::map<unsigned, WaylandWindow*>::const_iterator it = widget_map_.find(w);
402   return it == widget_map_.end() ? NULL : it->second;
403 }
404
405
406 // static
407 void WaylandDisplay::DisplayHandleGlobal(void *data,
408     struct wl_registry *registry,
409     uint32_t name,
410     const char *interface,
411     uint32_t version) {
412
413   WaylandDisplay* disp = static_cast<WaylandDisplay*>(data);
414
415   if (strcmp(interface, "wl_compositor") == 0) {
416     disp->compositor_ = static_cast<wl_compositor*>(
417         wl_registry_bind(registry, name, &wl_compositor_interface, 1));
418   } else if (strcmp(interface, "wl_output") == 0) {
419     WaylandScreen* screen = new WaylandScreen(disp->registry(), name);
420     if (!disp->screen_list_.empty())
421       NOTIMPLEMENTED() << "Multiple screens support is not implemented";
422
423     disp->screen_list_.push_back(screen);
424     // (kalyan) Support extended output.
425     disp->primary_screen_ = disp->screen_list_.front();
426   } else if (strcmp(interface, "wl_seat") == 0) {
427     WaylandInputDevice *input_device = new WaylandInputDevice(disp, name);
428     disp->input_list_.push_back(input_device);
429     disp->primary_input_ = disp->input_list_.front();
430   } else if (strcmp(interface, "wl_shm") == 0) {
431     disp->shm_ = static_cast<wl_shm*>(
432         wl_registry_bind(registry, name, &wl_shm_interface, 1));
433      WaylandCursor::InitializeCursorData(disp->shm_);
434   } else if (strcmp(interface, "wl_text_input_manager") == 0) {
435     disp->text_input_manager_ = static_cast<wl_text_input_manager*>(
436         wl_registry_bind(registry, name, &wl_text_input_manager_interface, 1));
437   } else {
438     disp->shell_->Initialize(registry, name, interface, version);
439   }
440 }
441
442 void WaylandDisplay::DisplayHandleOutputOnly(void *data,
443                                              struct wl_registry *registry,
444                                              uint32_t name,
445                                              const char *interface,
446                                              uint32_t version) {
447   WaylandDisplay* disp = static_cast<WaylandDisplay*>(data);
448
449   if (strcmp(interface, "wl_output") == 0) {
450     WaylandScreen* screen = new WaylandScreen(registry, name);
451     disp->look_ahead_screen_ = screen;
452   }
453 }
454
455 }  // namespace ozonewayland