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.
6 #include "ozone/wayland/display.h"
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"
24 namespace ozonewayland {
25 WaylandDisplay* WaylandDisplay::instance_ = NULL;
27 WaylandDisplay::WaylandDisplay() : SurfaceFactoryOzone(),
33 primary_screen_(NULL),
34 look_ahead_screen_(NULL),
36 display_poll_thread_(NULL),
41 processing_events_(false) {
44 WaylandDisplay::~WaylandDisplay() {
48 const std::list<WaylandScreen*>& WaylandDisplay::GetScreenList() const {
52 WaylandWindow* WaylandDisplay::GetWindow(unsigned window_handle) const {
53 return GetWidget(window_handle);
56 struct wl_text_input_manager* WaylandDisplay::GetTextInputManager() const {
57 return text_input_manager_;
60 void WaylandDisplay::FlushDisplay() {
61 wl_display_flush(display_);
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;
70 if (widget_map_.empty())
71 StopProcessingEvents();
74 gfx::AcceleratedWidget WaylandDisplay::GetNativeWindow(unsigned window_handle) {
75 // Ensure we are processing wayland event requests.
76 StartProcessingEvents();
77 WaylandWindow* widget = GetWidget(window_handle);
79 widget->RealizeAcceleratedWidget();
81 return (gfx::AcceleratedWidget)widget->egl_window();
84 bool WaylandDisplay::InitializeHardware() {
87 LOG(ERROR) << "WaylandDisplay failed to initialize hardware";
94 intptr_t WaylandDisplay::GetNativeDisplay() {
95 return (intptr_t)display_;
98 scoped_ptr<ui::SurfaceOzoneEGL> WaylandDisplay::CreateEGLSurfaceForWidget(
99 gfx::AcceleratedWidget w) {
100 return make_scoped_ptr<ui::SurfaceOzoneEGL>(new SurfaceOzoneWayland(w));
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);
117 LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
121 base::NativeLibrary egl_library = base::LoadNativeLibrary(
122 base::FilePath("libEGL.so.1"), &error);
125 LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
126 base::UnloadNativeLibrary(gles_library);
130 GLGetProcAddressProc get_proc_address =
131 reinterpret_cast<GLGetProcAddressProc>(
132 base::GetFunctionPointerFromNativeLibrary(
133 egl_library, "eglGetProcAddress"));
135 if (!get_proc_address) {
136 LOG(ERROR) << "eglGetProcAddress not found.";
137 base::UnloadNativeLibrary(egl_library);
138 base::UnloadNativeLibrary(gles_library);
142 setprocaddress.Run(get_proc_address);
143 add_gl_library.Run(egl_library);
144 add_gl_library.Run(gles_library);
149 WaylandDisplay::GetEGLSurfaceProperties(const int32* desired_list) {
150 static const EGLint kConfigAttribs[] = {
156 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
157 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
161 return kConfigAttribs;
164 void WaylandDisplay::SetWidgetState(unsigned w,
165 ui::WidgetState state,
171 CreateAcceleratedSurface(w);
176 WaylandWindow* widget = GetWidget(w);
177 widget->SetFullscreen();
178 widget->Resize(width, height);
183 WaylandWindow* widget = GetWidget(w);
189 WaylandWindow* widget = GetWidget(w);
195 WaylandWindow* widget = GetWidget(w);
197 widget->Resize(width, height);
201 NOTIMPLEMENTED() << " ACTIVE " << w;
204 NOTIMPLEMENTED() << " INACTIVE " << w;
207 NOTIMPLEMENTED() << " SHOW " << w;
210 NOTIMPLEMENTED() << " HIDE " << w;
217 void WaylandDisplay::SetWidgetTitle(unsigned w,
218 const base::string16& title) {
219 WaylandWindow* widget = GetWidget(w);
221 widget->SetWindowTitle(title);
224 void WaylandDisplay::SetWidgetCursor(int cursor_type) {
225 primary_input_->SetCursorType(cursor_type);
228 void WaylandDisplay::SetWidgetAttributes(unsigned widget,
232 ui::WidgetType type) {
233 WaylandWindow* window = GetWidget(widget);
234 WaylandWindow* parent_window = GetWidget(parent);
238 window->SetShellAttributes(WaylandWindow::TOPLEVEL);
240 case ui::WINDOWFRAMELESS:
244 DCHECK(parent_window);
245 window->SetShellAttributes(WaylandWindow::POPUP,
246 parent_window->ShellSurface(),
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.
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.
273 void WaylandDisplay::LookAheadOutputGeometry() {
274 wl_display* display = wl_display_connect(NULL);
278 static const struct wl_registry_listener registry_output = {
279 WaylandDisplay::DisplayHandleOutputOnly
282 wl_registry* registry = wl_display_get_registry(display);
283 wl_registry_add_listener(registry, ®istry_output, this);
285 if (wl_display_roundtrip(display) > 0) {
286 while (look_ahead_screen_->Geometry().IsEmpty())
287 wl_display_roundtrip(display);
289 ui::EventFactoryOzoneWayland* event_factory =
290 ui::EventFactoryOzoneWayland::GetInstance();
291 DCHECK(event_factory->GetOutputChangeObserver());
293 unsigned width = look_ahead_screen_->Geometry().width();
294 unsigned height = look_ahead_screen_->Geometry().height();
295 event_factory->GetOutputChangeObserver()->OnOutputSizeChanged(width,
299 if (look_ahead_screen_) {
300 delete look_ahead_screen_;
301 look_ahead_screen_ = NULL;
304 wl_registry_destroy(registry);
305 wl_display_flush(display);
306 wl_display_disconnect(display);
309 void WaylandDisplay::InitializeDisplay() {
311 display_ = wl_display_connect(NULL);
316 static const struct wl_registry_listener registry_all = {
317 WaylandDisplay::DisplayHandleGlobal
320 registry_ = wl_display_get_registry(display_);
321 wl_registry_add_listener(registry_, ®istry_all, this);
322 shell_ = new WaylandShell();
324 if (wl_display_roundtrip(display_) < 0) {
329 ui::WindowStateChangeHandler::SetInstance(this);
330 display_poll_thread_ = new WaylandDisplayPollThread(display_);
333 WaylandWindow* WaylandDisplay::CreateAcceleratedSurface(unsigned w) {
334 WaylandWindow* window = new WaylandWindow(w);
335 widget_map_[w] = window;
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;
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;
358 void WaylandDisplay::Terminate() {
359 if (!widget_map_.empty()) {
360 STLDeleteValues(&widget_map_);
364 for (std::list<WaylandInputDevice*>::iterator i = input_list_.begin();
365 i != input_list_.end(); ++i) {
369 for (std::list<WaylandScreen*>::iterator i = screen_list_.begin();
370 i != screen_list_.end(); ++i) {
374 screen_list_.clear();
377 WaylandCursor::Clear();
380 wl_compositor_destroy(compositor_);
384 wl_shm_destroy(shm_);
387 wl_registry_destroy(registry_);
389 delete display_poll_thread_;
392 wl_display_flush(display_);
393 wl_display_disconnect(display_);
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;
407 void WaylandDisplay::DisplayHandleGlobal(void *data,
408 struct wl_registry *registry,
410 const char *interface,
413 WaylandDisplay* disp = static_cast<WaylandDisplay*>(data);
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";
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 } else if (strcmp(interface, "wl_text_input_manager") == 0) {
434 disp->text_input_manager_ = static_cast<wl_text_input_manager*>(
435 wl_registry_bind(registry, name, &wl_text_input_manager_interface, 1));
437 disp->shell_->Initialize(registry, name, interface, version);
441 void WaylandDisplay::DisplayHandleOutputOnly(void *data,
442 struct wl_registry *registry,
444 const char *interface,
446 WaylandDisplay* disp = static_cast<WaylandDisplay*>(data);
448 if (strcmp(interface, "wl_output") == 0) {
449 WaylandScreen* screen = new WaylandScreen(registry, name);
450 disp->look_ahead_screen_ = screen;
454 } // namespace ozonewayland