Update To 11.40.268.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   switch (state) {
167     case ui::FULLSCREEN:
168     {
169       WaylandWindow* widget = GetWidget(w);
170       widget->SetFullscreen();
171       break;
172     }
173     case ui::MAXIMIZED:
174     {
175       WaylandWindow* widget = GetWidget(w);
176       widget->Maximize();
177       break;
178     }
179     case ui::MINIMIZED:
180     {
181       WaylandWindow* widget = GetWidget(w);
182       widget->Minimize();
183       break;
184     }
185     case ui::RESTORE:
186     {
187       WaylandWindow* widget = GetWidget(w);
188       widget->Restore();
189       break;
190     }
191     case ui::ACTIVE:
192       NOTIMPLEMENTED() << " ACTIVE " << w;
193       break;
194     case ui::INACTIVE:
195       NOTIMPLEMENTED() << " INACTIVE " << w;
196       break;
197     case ui::SHOW:
198     {
199       WaylandWindow* widget = GetWidget(w);
200       widget->Show();
201       break;
202     }
203     case ui::HIDE:
204       NOTIMPLEMENTED() << " HIDE " << w;
205       break;
206     default:
207       break;
208   }
209 }
210
211 void WaylandDisplay::SetWidgetTitle(unsigned w,
212                                     const base::string16& title) {
213   WaylandWindow* widget = GetWidget(w);
214   DCHECK(widget);
215   widget->SetWindowTitle(title);
216 }
217
218 void WaylandDisplay::SetWidgetCursor(int cursor_type) {
219   primary_input_->SetCursorType(cursor_type);
220 }
221
222 void WaylandDisplay::CreateWidget(unsigned widget,
223                                   unsigned parent,
224                                   unsigned x,
225                                   unsigned y,
226                                   ui::WidgetType type) {
227   DCHECK(!GetWidget(widget));
228   WaylandWindow* window = CreateAcceleratedSurface(widget);
229
230   WaylandWindow* parent_window = GetWidget(parent);
231   DCHECK(window);
232   switch (type) {
233   case ui::WINDOW:
234     window->SetShellAttributes(WaylandWindow::TOPLEVEL);
235     break;
236   case ui::WINDOWFRAMELESS:
237     NOTIMPLEMENTED();
238     break;
239   case ui::POPUP:
240     DCHECK(parent_window);
241     window->SetShellAttributes(WaylandWindow::POPUP,
242                                parent_window->ShellSurface(),
243                                x,
244                                y);
245     break;
246   default:
247     break;
248   }
249 }
250
251
252 // TODO(vignatti): GPU process conceptually is the one that deals with hardware
253 // details and therefore we assume that the window system connection should
254 // happen in there only. There's a glitch with Chrome though, that creates its
255 // frame contents requiring access to the window system, before the GPU process
256 // even exists. In other words, Chrome runs
257 // BrowserMainLoop::PreMainMessageLoopRun before GpuProcessHost::Get. If the
258 // assumption of window system connection belongs to the GPU process is valid,
259 // then I believe this Chrome behavior needs to be addressed upstream.
260 //
261 // For now, we create another window system connection to look ahead the needed
262 // output properties that Chrome (among others) need and then close right after
263 // that. I haven't measured how long it takes to open a Wayland connection,
264 // listen all the interface the compositor sends and close it, but _for_ _sure_
265 // it slows down the overall initialization time of Chromium targets.
266 // Therefore, this is something that has to be solved in the future, moving all
267 // Chrome tasks after GPU process is created.
268 //
269 void WaylandDisplay::LookAheadOutputGeometry() {
270   wl_display* display = wl_display_connect(NULL);
271   if (!display)
272     return;
273
274   static const struct wl_registry_listener registry_output = {
275     WaylandDisplay::DisplayHandleOutputOnly
276   };
277
278   wl_registry* registry = wl_display_get_registry(display);
279   wl_registry_add_listener(registry, &registry_output, this);
280
281   if (wl_display_roundtrip(display) > 0) {
282     while (look_ahead_screen_->Geometry().IsEmpty())
283       wl_display_roundtrip(display);
284
285     ui::EventFactoryOzoneWayland* event_factory =
286         ui::EventFactoryOzoneWayland::GetInstance();
287     DCHECK(event_factory->GetOutputChangeObserver());
288
289     unsigned width = look_ahead_screen_->Geometry().width();
290     unsigned height = look_ahead_screen_->Geometry().height();
291     event_factory->GetOutputChangeObserver()->OnOutputSizeChanged(width,
292                                                                   height);
293   }
294
295   if (look_ahead_screen_) {
296     delete look_ahead_screen_;
297     look_ahead_screen_ = NULL;
298   }
299
300   wl_registry_destroy(registry);
301   wl_display_flush(display);
302   wl_display_disconnect(display);
303 }
304
305 void WaylandDisplay::InitializeDisplay() {
306   DCHECK(!display_);
307   display_ = wl_display_connect(NULL);
308   if (!display_)
309     return;
310
311   instance_ = this;
312   static const struct wl_registry_listener registry_all = {
313     WaylandDisplay::DisplayHandleGlobal
314   };
315
316   registry_ = wl_display_get_registry(display_);
317   wl_registry_add_listener(registry_, &registry_all, this);
318   shell_ = new WaylandShell();
319
320   if (wl_display_roundtrip(display_) < 0) {
321     Terminate();
322     return;
323   }
324
325   ui::WindowStateChangeHandler::SetInstance(this);
326   display_poll_thread_ = new WaylandDisplayPollThread(display_);
327 }
328
329 WaylandWindow* WaylandDisplay::CreateAcceleratedSurface(unsigned w) {
330   WaylandWindow* window = new WaylandWindow(w);
331   widget_map_[w] = window;
332
333   return window;
334 }
335
336 void WaylandDisplay::StartProcessingEvents() {
337   DCHECK(display_poll_thread_);
338   // Start polling for wayland events.
339   if (!processing_events_) {
340     display_poll_thread_->StartProcessingEvents();
341     processing_events_ = true;
342   }
343 }
344
345 void WaylandDisplay::StopProcessingEvents() {
346   DCHECK(display_poll_thread_);
347   // Start polling for wayland events.
348   if (processing_events_) {
349     display_poll_thread_->StopProcessingEvents();
350     processing_events_ = false;
351   }
352 }
353
354 void WaylandDisplay::Terminate() {
355   if (!widget_map_.empty()) {
356     STLDeleteValues(&widget_map_);
357     widget_map_.clear();
358   }
359
360   for (std::list<WaylandInputDevice*>::iterator i = input_list_.begin();
361       i != input_list_.end(); ++i) {
362       delete *i;
363   }
364
365   for (std::list<WaylandScreen*>::iterator i = screen_list_.begin();
366       i != screen_list_.end(); ++i) {
367       delete *i;
368   }
369
370   screen_list_.clear();
371   input_list_.clear();
372
373   WaylandCursor::Clear();
374
375   if (compositor_)
376     wl_compositor_destroy(compositor_);
377
378   delete shell_;
379   if (shm_)
380     wl_shm_destroy(shm_);
381
382   if (registry_)
383     wl_registry_destroy(registry_);
384
385   delete display_poll_thread_;
386
387   if (display_) {
388     wl_display_flush(display_);
389     wl_display_disconnect(display_);
390     display_ = NULL;
391   }
392
393   instance_ = NULL;
394 }
395
396 WaylandWindow* WaylandDisplay::GetWidget(unsigned w) const {
397   std::map<unsigned, WaylandWindow*>::const_iterator it = widget_map_.find(w);
398   return it == widget_map_.end() ? NULL : it->second;
399 }
400
401
402 // static
403 void WaylandDisplay::DisplayHandleGlobal(void *data,
404     struct wl_registry *registry,
405     uint32_t name,
406     const char *interface,
407     uint32_t version) {
408
409   WaylandDisplay* disp = static_cast<WaylandDisplay*>(data);
410
411   if (strcmp(interface, "wl_compositor") == 0) {
412     disp->compositor_ = static_cast<wl_compositor*>(
413         wl_registry_bind(registry, name, &wl_compositor_interface, 1));
414   } else if (strcmp(interface, "wl_output") == 0) {
415     WaylandScreen* screen = new WaylandScreen(disp->registry(), name);
416     if (!disp->screen_list_.empty())
417       NOTIMPLEMENTED() << "Multiple screens support is not implemented";
418
419     disp->screen_list_.push_back(screen);
420     // (kalyan) Support extended output.
421     disp->primary_screen_ = disp->screen_list_.front();
422   } else if (strcmp(interface, "wl_seat") == 0) {
423     WaylandInputDevice *input_device = new WaylandInputDevice(disp, name);
424     disp->input_list_.push_back(input_device);
425     disp->primary_input_ = disp->input_list_.front();
426   } else if (strcmp(interface, "wl_shm") == 0) {
427     disp->shm_ = static_cast<wl_shm*>(
428         wl_registry_bind(registry, name, &wl_shm_interface, 1));
429      WaylandCursor::InitializeCursorData(disp->shm_);
430   } else if (strcmp(interface, "wl_text_input_manager") == 0) {
431     disp->text_input_manager_ = static_cast<wl_text_input_manager*>(
432         wl_registry_bind(registry, name, &wl_text_input_manager_interface, 1));
433   } else {
434     disp->shell_->Initialize(registry, name, interface, version);
435   }
436 }
437
438 void WaylandDisplay::DisplayHandleOutputOnly(void *data,
439                                              struct wl_registry *registry,
440                                              uint32_t name,
441                                              const char *interface,
442                                              uint32_t version) {
443   WaylandDisplay* disp = static_cast<WaylandDisplay*>(data);
444
445   if (strcmp(interface, "wl_output") == 0) {
446     WaylandScreen* screen = new WaylandScreen(registry, name);
447     disp->look_ahead_screen_ = screen;
448   }
449 }
450
451 }  // namespace ozonewayland