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) {
169 WaylandWindow* widget = GetWidget(w);
170 widget->SetFullscreen();
175 WaylandWindow* widget = GetWidget(w);
181 WaylandWindow* widget = GetWidget(w);
187 WaylandWindow* widget = GetWidget(w);
192 NOTIMPLEMENTED() << " ACTIVE " << w;
195 NOTIMPLEMENTED() << " INACTIVE " << w;
199 WaylandWindow* widget = GetWidget(w);
204 NOTIMPLEMENTED() << " HIDE " << w;
211 void WaylandDisplay::SetWidgetTitle(unsigned w,
212 const base::string16& title) {
213 WaylandWindow* widget = GetWidget(w);
215 widget->SetWindowTitle(title);
218 void WaylandDisplay::SetWidgetCursor(int cursor_type) {
219 primary_input_->SetCursorType(cursor_type);
222 void WaylandDisplay::CreateWidget(unsigned widget,
226 ui::WidgetType type) {
227 DCHECK(!GetWidget(widget));
228 WaylandWindow* window = CreateAcceleratedSurface(widget);
230 WaylandWindow* parent_window = GetWidget(parent);
234 window->SetShellAttributes(WaylandWindow::TOPLEVEL);
236 case ui::WINDOWFRAMELESS:
240 DCHECK(parent_window);
241 window->SetShellAttributes(WaylandWindow::POPUP,
242 parent_window->ShellSurface(),
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.
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.
269 void WaylandDisplay::LookAheadOutputGeometry() {
270 wl_display* display = wl_display_connect(NULL);
274 static const struct wl_registry_listener registry_output = {
275 WaylandDisplay::DisplayHandleOutputOnly
278 wl_registry* registry = wl_display_get_registry(display);
279 wl_registry_add_listener(registry, ®istry_output, this);
281 if (wl_display_roundtrip(display) > 0) {
282 while (look_ahead_screen_->Geometry().IsEmpty())
283 wl_display_roundtrip(display);
285 ui::EventFactoryOzoneWayland* event_factory =
286 ui::EventFactoryOzoneWayland::GetInstance();
287 DCHECK(event_factory->GetOutputChangeObserver());
289 unsigned width = look_ahead_screen_->Geometry().width();
290 unsigned height = look_ahead_screen_->Geometry().height();
291 event_factory->GetOutputChangeObserver()->OnOutputSizeChanged(width,
295 if (look_ahead_screen_) {
296 delete look_ahead_screen_;
297 look_ahead_screen_ = NULL;
300 wl_registry_destroy(registry);
301 wl_display_flush(display);
302 wl_display_disconnect(display);
305 void WaylandDisplay::InitializeDisplay() {
307 display_ = wl_display_connect(NULL);
312 static const struct wl_registry_listener registry_all = {
313 WaylandDisplay::DisplayHandleGlobal
316 registry_ = wl_display_get_registry(display_);
317 wl_registry_add_listener(registry_, ®istry_all, this);
318 shell_ = new WaylandShell();
320 if (wl_display_roundtrip(display_) < 0) {
325 ui::WindowStateChangeHandler::SetInstance(this);
326 display_poll_thread_ = new WaylandDisplayPollThread(display_);
329 WaylandWindow* WaylandDisplay::CreateAcceleratedSurface(unsigned w) {
330 WaylandWindow* window = new WaylandWindow(w);
331 widget_map_[w] = window;
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;
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;
354 void WaylandDisplay::Terminate() {
355 if (!widget_map_.empty()) {
356 STLDeleteValues(&widget_map_);
360 for (std::list<WaylandInputDevice*>::iterator i = input_list_.begin();
361 i != input_list_.end(); ++i) {
365 for (std::list<WaylandScreen*>::iterator i = screen_list_.begin();
366 i != screen_list_.end(); ++i) {
370 screen_list_.clear();
373 WaylandCursor::Clear();
376 wl_compositor_destroy(compositor_);
380 wl_shm_destroy(shm_);
383 wl_registry_destroy(registry_);
385 delete display_poll_thread_;
388 wl_display_flush(display_);
389 wl_display_disconnect(display_);
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;
403 void WaylandDisplay::DisplayHandleGlobal(void *data,
404 struct wl_registry *registry,
406 const char *interface,
409 WaylandDisplay* disp = static_cast<WaylandDisplay*>(data);
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";
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));
434 disp->shell_->Initialize(registry, name, interface, version);
438 void WaylandDisplay::DisplayHandleOutputOnly(void *data,
439 struct wl_registry *registry,
441 const char *interface,
443 WaylandDisplay* disp = static_cast<WaylandDisplay*>(data);
445 if (strcmp(interface, "wl_output") == 0) {
446 WaylandScreen* screen = new WaylandScreen(registry, name);
447 disp->look_ahead_screen_ = screen;
451 } // namespace ozonewayland