|  | // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "components/exo/wayland/server.h" | 
|  |  | 
|  | #include <linux/input.h> | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  | #include <wayland-server-core.h> | 
|  | #include <wayland-server-protocol-core.h> | 
|  | #include <xdg-shell-unstable-v5-server-protocol.h> | 
|  | #include <algorithm> | 
|  | #include <utility> | 
|  |  | 
|  | #include "ash/display/display_info.h" | 
|  | #include "ash/display/display_manager.h" | 
|  | #include "ash/shell.h" | 
|  | #include "base/bind.h" | 
|  | #include "base/cancelable_callback.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/strings/utf_string_conversions.h" | 
|  | #include "components/exo/buffer.h" | 
|  | #include "components/exo/display.h" | 
|  | #include "components/exo/keyboard.h" | 
|  | #include "components/exo/keyboard_delegate.h" | 
|  | #include "components/exo/pointer.h" | 
|  | #include "components/exo/pointer_delegate.h" | 
|  | #include "components/exo/shared_memory.h" | 
|  | #include "components/exo/shell_surface.h" | 
|  | #include "components/exo/sub_surface.h" | 
|  | #include "components/exo/surface.h" | 
|  | #include "components/exo/touch.h" | 
|  | #include "components/exo/touch_delegate.h" | 
|  | #include "third_party/skia/include/core/SkRegion.h" | 
|  | #include "ui/aura/window_property.h" | 
|  | #include "ui/events/keycodes/dom/keycode_converter.h" | 
|  |  | 
|  | #if defined(USE_OZONE) | 
|  | #include <wayland-drm-server-protocol.h> | 
|  | #endif | 
|  |  | 
|  | #if defined(USE_XKBCOMMON) | 
|  | #include <xkbcommon/xkbcommon.h> | 
|  | #include "ui/events/keycodes/scoped_xkb.h" | 
|  | #endif | 
|  |  | 
|  | DECLARE_WINDOW_PROPERTY_TYPE(wl_resource*); | 
|  |  | 
|  | namespace exo { | 
|  | namespace wayland { | 
|  | namespace { | 
|  |  | 
|  | template <class T> | 
|  | T* GetUserDataAs(wl_resource* resource) { | 
|  | return static_cast<T*>(wl_resource_get_user_data(resource)); | 
|  | } | 
|  |  | 
|  | template <class T> | 
|  | scoped_ptr<T> TakeUserDataAs(wl_resource* resource) { | 
|  | scoped_ptr<T> user_data = make_scoped_ptr(GetUserDataAs<T>(resource)); | 
|  | wl_resource_set_user_data(resource, nullptr); | 
|  | return user_data; | 
|  | } | 
|  |  | 
|  | template <class T> | 
|  | void DestroyUserData(wl_resource* resource) { | 
|  | TakeUserDataAs<T>(resource); | 
|  | } | 
|  |  | 
|  | template <class T> | 
|  | void SetImplementation(wl_resource* resource, | 
|  | const void* implementation, | 
|  | scoped_ptr<T> user_data) { | 
|  | wl_resource_set_implementation(resource, implementation, user_data.release(), | 
|  | DestroyUserData<T>); | 
|  | } | 
|  |  | 
|  | // A property key containing the surface resource that is associated with | 
|  | // window. If unset, no surface resource is associated with window. | 
|  | DEFINE_WINDOW_PROPERTY_KEY(wl_resource*, kSurfaceResourceKey, nullptr); | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_buffer_interface: | 
|  |  | 
|  | void buffer_destroy(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | const struct wl_buffer_interface buffer_implementation = {buffer_destroy}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_surface_interface: | 
|  |  | 
|  | void surface_destroy(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | void surface_attach(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* buffer, | 
|  | int32_t x, | 
|  | int32_t y) { | 
|  | // TODO(reveman): Implement buffer offset support. | 
|  | if (x || y) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | GetUserDataAs<Surface>(resource) | 
|  | ->Attach(buffer ? GetUserDataAs<Buffer>(buffer) : nullptr); | 
|  | } | 
|  |  | 
|  | void surface_damage(wl_client* client, | 
|  | wl_resource* resource, | 
|  | int32_t x, | 
|  | int32_t y, | 
|  | int32_t width, | 
|  | int32_t height) { | 
|  | GetUserDataAs<Surface>(resource)->Damage(gfx::Rect(x, y, width, height)); | 
|  | } | 
|  |  | 
|  | void HandleSurfaceFrameCallback(wl_resource* resource, | 
|  | base::TimeTicks frame_time) { | 
|  | if (!frame_time.is_null()) { | 
|  | wl_callback_send_done(resource, | 
|  | (frame_time - base::TimeTicks()).InMilliseconds()); | 
|  | // TODO(reveman): Remove this potentially blocking flush and instead watch | 
|  | // the file descriptor to be ready for write without blocking. | 
|  | wl_client_flush(wl_resource_get_client(resource)); | 
|  | } | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | void surface_frame(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t callback) { | 
|  | wl_resource* callback_resource = | 
|  | wl_resource_create(client, &wl_callback_interface, 1, callback); | 
|  | if (!callback_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // base::Unretained is safe as the resource owns the callback. | 
|  | scoped_ptr<base::CancelableCallback<void(base::TimeTicks)>> | 
|  | cancelable_callback( | 
|  | new base::CancelableCallback<void(base::TimeTicks)>(base::Bind( | 
|  | &HandleSurfaceFrameCallback, base::Unretained(callback_resource)))); | 
|  |  | 
|  | GetUserDataAs<Surface>(resource) | 
|  | ->RequestFrameCallback(cancelable_callback->callback()); | 
|  |  | 
|  | SetImplementation(callback_resource, nullptr, std::move(cancelable_callback)); | 
|  | } | 
|  |  | 
|  | void surface_set_opaque_region(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* region_resource) { | 
|  | GetUserDataAs<Surface>(resource)->SetOpaqueRegion( | 
|  | region_resource ? *GetUserDataAs<SkRegion>(region_resource) | 
|  | : SkRegion(SkIRect::MakeEmpty())); | 
|  | } | 
|  |  | 
|  | void surface_set_input_region(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* region_resource) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void surface_commit(wl_client* client, wl_resource* resource) { | 
|  | GetUserDataAs<Surface>(resource)->Commit(); | 
|  | } | 
|  |  | 
|  | void surface_set_buffer_transform(wl_client* client, | 
|  | wl_resource* resource, | 
|  | int transform) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void surface_set_buffer_scale(wl_client* client, | 
|  | wl_resource* resource, | 
|  | int32_t scale) { | 
|  | if (scale < 1) { | 
|  | wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_SCALE, | 
|  | "buffer scale must be at least one " | 
|  | "('%d' specified)", | 
|  | scale); | 
|  | return; | 
|  | } | 
|  |  | 
|  | GetUserDataAs<Surface>(resource)->SetBufferScale(scale); | 
|  | } | 
|  |  | 
|  | const struct wl_surface_interface surface_implementation = { | 
|  | surface_destroy, | 
|  | surface_attach, | 
|  | surface_damage, | 
|  | surface_frame, | 
|  | surface_set_opaque_region, | 
|  | surface_set_input_region, | 
|  | surface_commit, | 
|  | surface_set_buffer_transform, | 
|  | surface_set_buffer_scale}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_region_interface: | 
|  |  | 
|  | void region_destroy(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | void region_add(wl_client* client, | 
|  | wl_resource* resource, | 
|  | int32_t x, | 
|  | int32_t y, | 
|  | int32_t width, | 
|  | int32_t height) { | 
|  | GetUserDataAs<SkRegion>(resource) | 
|  | ->op(SkIRect::MakeXYWH(x, y, width, height), SkRegion::kUnion_Op); | 
|  | } | 
|  |  | 
|  | static void region_subtract(wl_client* client, | 
|  | wl_resource* resource, | 
|  | int32_t x, | 
|  | int32_t y, | 
|  | int32_t width, | 
|  | int32_t height) { | 
|  | GetUserDataAs<SkRegion>(resource) | 
|  | ->op(SkIRect::MakeXYWH(x, y, width, height), SkRegion::kDifference_Op); | 
|  | } | 
|  |  | 
|  | const struct wl_region_interface region_implementation = { | 
|  | region_destroy, region_add, region_subtract}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_compositor_interface: | 
|  |  | 
|  | void compositor_create_surface(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id) { | 
|  | scoped_ptr<Surface> surface = | 
|  | GetUserDataAs<Display>(resource)->CreateSurface(); | 
|  | DCHECK(surface); | 
|  |  | 
|  | wl_resource* surface_resource = wl_resource_create( | 
|  | client, &wl_surface_interface, wl_resource_get_version(resource), id); | 
|  | if (!surface_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Set the surface resource property for type-checking downcast support. | 
|  | surface->SetProperty(kSurfaceResourceKey, surface_resource); | 
|  |  | 
|  | SetImplementation(surface_resource, &surface_implementation, | 
|  | std::move(surface)); | 
|  | } | 
|  |  | 
|  | void compositor_create_region(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id) { | 
|  | scoped_ptr<SkRegion> region(new SkRegion); | 
|  |  | 
|  | wl_resource* region_resource = | 
|  | wl_resource_create(client, &wl_region_interface, 1, id); | 
|  | if (!region_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SetImplementation(region_resource, ®ion_implementation, std::move(region)); | 
|  | } | 
|  |  | 
|  | const struct wl_compositor_interface compositor_implementation = { | 
|  | compositor_create_surface, compositor_create_region}; | 
|  |  | 
|  | const uint32_t compositor_version = 3; | 
|  |  | 
|  | void bind_compositor(wl_client* client, | 
|  | void* data, | 
|  | uint32_t version, | 
|  | uint32_t id) { | 
|  | wl_resource* resource = | 
|  | wl_resource_create(client, &wl_compositor_interface, | 
|  | std::min(version, compositor_version), id); | 
|  | if (!resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource_set_implementation(resource, &compositor_implementation, data, | 
|  | nullptr); | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_shm_pool_interface: | 
|  |  | 
|  | const struct shm_supported_format { | 
|  | uint32_t shm_format; | 
|  | gfx::BufferFormat buffer_format; | 
|  | } shm_supported_formats[] = { | 
|  | {WL_SHM_FORMAT_XBGR8888, gfx::BufferFormat::RGBX_8888}, | 
|  | {WL_SHM_FORMAT_ABGR8888, gfx::BufferFormat::RGBA_8888}, | 
|  | {WL_SHM_FORMAT_XRGB8888, gfx::BufferFormat::BGRX_8888}, | 
|  | {WL_SHM_FORMAT_ARGB8888, gfx::BufferFormat::BGRA_8888}}; | 
|  |  | 
|  | void shm_pool_create_buffer(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | int32_t offset, | 
|  | int32_t width, | 
|  | int32_t height, | 
|  | int32_t stride, | 
|  | uint32_t format) { | 
|  | const auto* supported_format = | 
|  | std::find_if(shm_supported_formats, | 
|  | shm_supported_formats + arraysize(shm_supported_formats), | 
|  | [format](const shm_supported_format& supported_format) { | 
|  | return supported_format.shm_format == format; | 
|  | }); | 
|  | if (supported_format == | 
|  | (shm_supported_formats + arraysize(shm_supported_formats))) { | 
|  | wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FORMAT, | 
|  | "invalid format 0x%x", format); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (offset < 0) { | 
|  | wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FORMAT, | 
|  | "invalid offset %d", offset); | 
|  | return; | 
|  | } | 
|  |  | 
|  | scoped_ptr<Buffer> buffer = | 
|  | GetUserDataAs<SharedMemory>(resource) | 
|  | ->CreateBuffer(gfx::Size(width, height), | 
|  | supported_format->buffer_format, offset, stride); | 
|  | if (!buffer) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource* buffer_resource = | 
|  | wl_resource_create(client, &wl_buffer_interface, 1, id); | 
|  | if (!buffer_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | buffer->set_release_callback( | 
|  | base::Bind(&wl_buffer_send_release, base::Unretained(buffer_resource))); | 
|  |  | 
|  | SetImplementation(buffer_resource, &buffer_implementation, std::move(buffer)); | 
|  | } | 
|  |  | 
|  | void shm_pool_destroy(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | void shm_pool_resize(wl_client* client, wl_resource* resource, int32_t size) { | 
|  | // Nothing to do here. | 
|  | } | 
|  |  | 
|  | const struct wl_shm_pool_interface shm_pool_implementation = { | 
|  | shm_pool_create_buffer, shm_pool_destroy, shm_pool_resize}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_shm_interface: | 
|  |  | 
|  | void shm_create_pool(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | int fd, | 
|  | int32_t size) { | 
|  | scoped_ptr<SharedMemory> shared_memory = | 
|  | GetUserDataAs<Display>(resource) | 
|  | ->CreateSharedMemory(base::FileDescriptor(fd, true), size); | 
|  | if (!shared_memory) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource* shm_pool_resource = | 
|  | wl_resource_create(client, &wl_shm_pool_interface, 1, id); | 
|  | if (!shm_pool_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SetImplementation(shm_pool_resource, &shm_pool_implementation, | 
|  | std::move(shared_memory)); | 
|  | } | 
|  |  | 
|  | const struct wl_shm_interface shm_implementation = {shm_create_pool}; | 
|  |  | 
|  | void bind_shm(wl_client* client, void* data, uint32_t version, uint32_t id) { | 
|  | wl_resource* resource = wl_resource_create(client, &wl_shm_interface, 1, id); | 
|  | if (!resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource_set_implementation(resource, &shm_implementation, data, nullptr); | 
|  |  | 
|  | for (const auto& supported_format : shm_supported_formats) | 
|  | wl_shm_send_format(resource, supported_format.shm_format); | 
|  | } | 
|  |  | 
|  | #if defined(USE_OZONE) | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_drm_interface: | 
|  |  | 
|  | const struct drm_supported_format { | 
|  | uint32_t drm_format; | 
|  | gfx::BufferFormat buffer_format; | 
|  | } drm_supported_formats[] = { | 
|  | {WL_DRM_FORMAT_XBGR8888, gfx::BufferFormat::RGBX_8888}, | 
|  | {WL_DRM_FORMAT_ABGR8888, gfx::BufferFormat::RGBA_8888}, | 
|  | {WL_DRM_FORMAT_XRGB8888, gfx::BufferFormat::BGRX_8888}, | 
|  | {WL_DRM_FORMAT_ARGB8888, gfx::BufferFormat::BGRA_8888}}; | 
|  |  | 
|  | void drm_authenticate(wl_client* client, wl_resource* resource, uint32_t id) { | 
|  | wl_drm_send_authenticated(resource); | 
|  | } | 
|  |  | 
|  | void drm_create_buffer(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | uint32_t name, | 
|  | int32_t width, | 
|  | int32_t height, | 
|  | uint32_t stride, | 
|  | uint32_t format) { | 
|  | wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_NAME, | 
|  | "GEM names are not supported"); | 
|  | } | 
|  |  | 
|  | void drm_create_planar_buffer(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | uint32_t name, | 
|  | int32_t width, | 
|  | int32_t height, | 
|  | uint32_t format, | 
|  | int32_t offset0, | 
|  | int32_t stride0, | 
|  | int32_t offset1, | 
|  | int32_t stride1, | 
|  | int32_t offset2, | 
|  | int32_t stride3) { | 
|  | wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_NAME, | 
|  | "GEM names are not supported"); | 
|  | } | 
|  |  | 
|  | void drm_create_prime_buffer(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | int32_t name, | 
|  | int32_t width, | 
|  | int32_t height, | 
|  | uint32_t format, | 
|  | int32_t offset0, | 
|  | int32_t stride0, | 
|  | int32_t offset1, | 
|  | int32_t stride1, | 
|  | int32_t offset2, | 
|  | int32_t stride2) { | 
|  | const auto* supported_format = | 
|  | std::find_if(drm_supported_formats, | 
|  | drm_supported_formats + arraysize(drm_supported_formats), | 
|  | [format](const drm_supported_format& supported_format) { | 
|  | return supported_format.drm_format == format; | 
|  | }); | 
|  | if (supported_format == | 
|  | (drm_supported_formats + arraysize(drm_supported_formats))) { | 
|  | wl_resource_post_error(resource, WL_DRM_ERROR_INVALID_FORMAT, | 
|  | "invalid format 0x%x", format); | 
|  | return; | 
|  | } | 
|  |  | 
|  | scoped_ptr<Buffer> buffer = | 
|  | GetUserDataAs<Display>(resource) | 
|  | ->CreatePrimeBuffer(base::ScopedFD(name), gfx::Size(width, height), | 
|  | supported_format->buffer_format, stride0); | 
|  | if (!buffer) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource* buffer_resource = | 
|  | wl_resource_create(client, &wl_buffer_interface, 1, id); | 
|  | if (!buffer_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | buffer->set_release_callback( | 
|  | base::Bind(&wl_buffer_send_release, base::Unretained(buffer_resource))); | 
|  |  | 
|  | SetImplementation(buffer_resource, &buffer_implementation, std::move(buffer)); | 
|  | } | 
|  |  | 
|  | const struct wl_drm_interface drm_implementation = { | 
|  | drm_authenticate, drm_create_buffer, drm_create_planar_buffer, | 
|  | drm_create_prime_buffer}; | 
|  |  | 
|  | const uint32_t drm_version = 2; | 
|  |  | 
|  | void bind_drm(wl_client* client, void* data, uint32_t version, uint32_t id) { | 
|  | wl_resource* resource = wl_resource_create( | 
|  | client, &wl_drm_interface, std::min(version, drm_version), id); | 
|  | if (!resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  | wl_resource_set_implementation(resource, &drm_implementation, data, nullptr); | 
|  |  | 
|  | if (version >= 2) | 
|  | wl_drm_send_capabilities(resource, WL_DRM_CAPABILITY_PRIME); | 
|  |  | 
|  | for (const auto& supported_format : drm_supported_formats) | 
|  | wl_drm_send_format(resource, supported_format.drm_format); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_subsurface_interface: | 
|  |  | 
|  | void subsurface_destroy(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | void subsurface_set_position(wl_client* client, | 
|  | wl_resource* resource, | 
|  | int32_t x, | 
|  | int32_t y) { | 
|  | GetUserDataAs<SubSurface>(resource)->SetPosition(gfx::Point(x, y)); | 
|  | } | 
|  |  | 
|  | void subsurface_place_above(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* reference_resource) { | 
|  | GetUserDataAs<SubSurface>(resource) | 
|  | ->PlaceAbove(GetUserDataAs<Surface>(reference_resource)); | 
|  | } | 
|  |  | 
|  | void subsurface_place_below(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* sibling_resource) { | 
|  | GetUserDataAs<SubSurface>(resource) | 
|  | ->PlaceBelow(GetUserDataAs<Surface>(sibling_resource)); | 
|  | } | 
|  |  | 
|  | void subsurface_set_sync(wl_client* client, wl_resource* resource) { | 
|  | GetUserDataAs<SubSurface>(resource)->SetCommitBehavior(true); | 
|  | } | 
|  |  | 
|  | void subsurface_set_desync(wl_client* client, wl_resource* resource) { | 
|  | GetUserDataAs<SubSurface>(resource)->SetCommitBehavior(false); | 
|  | } | 
|  |  | 
|  | const struct wl_subsurface_interface subsurface_implementation = { | 
|  | subsurface_destroy,     subsurface_set_position, subsurface_place_above, | 
|  | subsurface_place_below, subsurface_set_sync,     subsurface_set_desync}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_subcompositor_interface: | 
|  |  | 
|  | void subcompositor_destroy(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | void subcompositor_get_subsurface(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | wl_resource* surface, | 
|  | wl_resource* parent) { | 
|  | scoped_ptr<SubSurface> subsurface = | 
|  | GetUserDataAs<Display>(resource)->CreateSubSurface( | 
|  | GetUserDataAs<Surface>(surface), GetUserDataAs<Surface>(parent)); | 
|  | if (!subsurface) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource* subsurface_resource = | 
|  | wl_resource_create(client, &wl_subsurface_interface, 1, id); | 
|  | if (!subsurface_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SetImplementation(subsurface_resource, &subsurface_implementation, | 
|  | std::move(subsurface)); | 
|  | } | 
|  |  | 
|  | const struct wl_subcompositor_interface subcompositor_implementation = { | 
|  | subcompositor_destroy, subcompositor_get_subsurface}; | 
|  |  | 
|  | void bind_subcompositor(wl_client* client, | 
|  | void* data, | 
|  | uint32_t version, | 
|  | uint32_t id) { | 
|  | wl_resource* resource = | 
|  | wl_resource_create(client, &wl_subcompositor_interface, 1, id); | 
|  | if (!resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  | wl_resource_set_implementation(resource, &subcompositor_implementation, data, | 
|  | nullptr); | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_shell_surface_interface: | 
|  |  | 
|  | void shell_surface_pong(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t serial) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void shell_surface_move(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* seat_resource, | 
|  | uint32_t serial) { | 
|  | GetUserDataAs<ShellSurface>(resource)->Move(); | 
|  | } | 
|  |  | 
|  | void shell_surface_resize(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* seat_resource, | 
|  | uint32_t serial, | 
|  | uint32_t edges) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void shell_surface_set_toplevel(wl_client* client, wl_resource* resource) { | 
|  | GetUserDataAs<ShellSurface>(resource)->Init(); | 
|  | } | 
|  |  | 
|  | void shell_surface_set_transient(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* parent_resource, | 
|  | int x, | 
|  | int y, | 
|  | uint32_t flags) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void shell_surface_set_fullscreen(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t method, | 
|  | uint32_t framerate, | 
|  | wl_resource* output_resource) { | 
|  | GetUserDataAs<ShellSurface>(resource)->Init(); | 
|  | GetUserDataAs<ShellSurface>(resource)->SetFullscreen(true); | 
|  | } | 
|  |  | 
|  | void shell_surface_set_popup(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* seat_resource, | 
|  | uint32_t serial, | 
|  | wl_resource* parent_resource, | 
|  | int32_t x, | 
|  | int32_t y, | 
|  | uint32_t flags) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void shell_surface_set_maximized(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* output_resource) { | 
|  | GetUserDataAs<ShellSurface>(resource)->Init(); | 
|  | GetUserDataAs<ShellSurface>(resource)->Maximize(); | 
|  | } | 
|  |  | 
|  | void shell_surface_set_title(wl_client* client, | 
|  | wl_resource* resource, | 
|  | const char* title) { | 
|  | GetUserDataAs<ShellSurface>(resource) | 
|  | ->SetTitle(base::string16(base::UTF8ToUTF16(title))); | 
|  | } | 
|  |  | 
|  | void shell_surface_set_class(wl_client* client, | 
|  | wl_resource* resource, | 
|  | const char* clazz) { | 
|  | GetUserDataAs<ShellSurface>(resource)->SetApplicationId(clazz); | 
|  | } | 
|  |  | 
|  | const struct wl_shell_surface_interface shell_surface_implementation = { | 
|  | shell_surface_pong,          shell_surface_move, | 
|  | shell_surface_resize,        shell_surface_set_toplevel, | 
|  | shell_surface_set_transient, shell_surface_set_fullscreen, | 
|  | shell_surface_set_popup,     shell_surface_set_maximized, | 
|  | shell_surface_set_title,     shell_surface_set_class}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_shell_interface: | 
|  |  | 
|  | void HandleShellSurfaceConfigureCallback(wl_resource* resource, | 
|  | const gfx::Size& size) { | 
|  | wl_shell_surface_send_configure(resource, WL_SHELL_SURFACE_RESIZE_NONE, | 
|  | size.width(), size.height()); | 
|  | } | 
|  |  | 
|  | void shell_get_shell_surface(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | wl_resource* surface) { | 
|  | scoped_ptr<ShellSurface> shell_surface = | 
|  | GetUserDataAs<Display>(resource) | 
|  | ->CreateShellSurface(GetUserDataAs<Surface>(surface)); | 
|  | if (!shell_surface) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource* shell_surface_resource = | 
|  | wl_resource_create(client, &wl_shell_surface_interface, 1, id); | 
|  | if (!shell_surface_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | shell_surface->set_surface_destroyed_callback(base::Bind( | 
|  | &wl_resource_destroy, base::Unretained(shell_surface_resource))); | 
|  |  | 
|  | shell_surface->set_configure_callback( | 
|  | base::Bind(&HandleShellSurfaceConfigureCallback, | 
|  | base::Unretained(shell_surface_resource))); | 
|  |  | 
|  | SetImplementation(shell_surface_resource, &shell_surface_implementation, | 
|  | std::move(shell_surface)); | 
|  | } | 
|  |  | 
|  | const struct wl_shell_interface shell_implementation = { | 
|  | shell_get_shell_surface}; | 
|  |  | 
|  | void bind_shell(wl_client* client, void* data, uint32_t version, uint32_t id) { | 
|  | wl_resource* resource = | 
|  | wl_resource_create(client, &wl_shell_interface, 1, id); | 
|  | if (!resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  | wl_resource_set_implementation(resource, &shell_implementation, data, | 
|  | nullptr); | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_output_interface: | 
|  |  | 
|  | const uint32_t output_version = 2; | 
|  |  | 
|  | void bind_output(wl_client* client, void* data, uint32_t version, uint32_t id) { | 
|  | wl_resource* resource = wl_resource_create( | 
|  | client, &wl_output_interface, std::min(version, output_version), id); | 
|  | if (!resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // TODO(reveman): Watch for display changes and report them. | 
|  | // TODO(reveman): Multi-display support. | 
|  | ash::DisplayManager* display_manager = | 
|  | ash::Shell::GetInstance()->display_manager(); | 
|  | const gfx::Display& primary = display_manager->GetPrimaryDisplayCandidate(); | 
|  |  | 
|  | const ash::DisplayInfo& info = display_manager->GetDisplayInfo(primary.id()); | 
|  | const float kInchInMm = 25.4f; | 
|  | const char* kUnknownMake = "unknown"; | 
|  | const char* kUnknownModel = "unknown"; | 
|  | gfx::Rect bounds = info.bounds_in_native(); | 
|  | // TODO(reveman): Send the actual active device rotation. | 
|  | wl_output_send_geometry( | 
|  | resource, bounds.x(), bounds.y(), | 
|  | static_cast<int>(kInchInMm * bounds.width() / info.device_dpi()), | 
|  | static_cast<int>(kInchInMm * bounds.height() / info.device_dpi()), | 
|  | WL_OUTPUT_SUBPIXEL_UNKNOWN, kUnknownMake, kUnknownModel, | 
|  | WL_OUTPUT_TRANSFORM_NORMAL); | 
|  |  | 
|  | // TODO(reveman): Send correct device scale factor when surface API respects | 
|  | // scale. | 
|  | if (version >= WL_OUTPUT_SCALE_SINCE_VERSION) | 
|  | wl_output_send_scale(resource, primary.device_scale_factor()); | 
|  |  | 
|  | // TODO(reveman): Send real list of modes after adding multi-display support. | 
|  | wl_output_send_mode(resource, | 
|  | WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, | 
|  | bounds.width(), bounds.height(), static_cast<int>(60000)); | 
|  |  | 
|  | if (version >= WL_OUTPUT_DONE_SINCE_VERSION) | 
|  | wl_output_send_done(resource); | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // xdg_surface_interface: | 
|  |  | 
|  | void xdg_surface_destroy(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | void xdg_surface_set_parent(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* parent) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void xdg_surface_set_title(wl_client* client, | 
|  | wl_resource* resource, | 
|  | const char* title) { | 
|  | GetUserDataAs<ShellSurface>(resource) | 
|  | ->SetTitle(base::string16(base::UTF8ToUTF16(title))); | 
|  | } | 
|  |  | 
|  | void xdg_surface_set_add_id(wl_client* client, | 
|  | wl_resource* resource, | 
|  | const char* app_id) { | 
|  | GetUserDataAs<ShellSurface>(resource)->SetApplicationId(app_id); | 
|  | } | 
|  |  | 
|  | void xdg_surface_show_window_menu(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* seat, | 
|  | uint32_t serial, | 
|  | int32_t x, | 
|  | int32_t y) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void xdg_surface_move(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* seat, | 
|  | uint32_t serial) { | 
|  | GetUserDataAs<ShellSurface>(resource)->Move(); | 
|  | } | 
|  |  | 
|  | void xdg_surface_resize(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* seat, | 
|  | uint32_t serial, | 
|  | uint32_t edges) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void xdg_surface_ack_configure(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t serial) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void xdg_surface_set_window_geometry(wl_client* client, | 
|  | wl_resource* resource, | 
|  | int32_t x, | 
|  | int32_t y, | 
|  | int32_t width, | 
|  | int32_t height) { | 
|  | GetUserDataAs<ShellSurface>(resource) | 
|  | ->SetGeometry(gfx::Rect(x, y, width, height)); | 
|  | } | 
|  |  | 
|  | void xdg_surface_set_maximized(wl_client* client, wl_resource* resource) { | 
|  | GetUserDataAs<ShellSurface>(resource)->Maximize(); | 
|  | } | 
|  |  | 
|  | void xdg_surface_unset_maximized(wl_client* client, wl_resource* resource) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void xdg_surface_set_fullscreen(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* output) { | 
|  | GetUserDataAs<ShellSurface>(resource)->SetFullscreen(true); | 
|  | } | 
|  |  | 
|  | void xdg_surface_unset_fullscreen(wl_client* client, wl_resource* resource) { | 
|  | GetUserDataAs<ShellSurface>(resource)->SetFullscreen(false); | 
|  | } | 
|  |  | 
|  | void xdg_surface_set_minimized(wl_client* client, wl_resource* resource) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | const struct xdg_surface_interface xdg_surface_implementation = { | 
|  | xdg_surface_destroy, | 
|  | xdg_surface_set_parent, | 
|  | xdg_surface_set_title, | 
|  | xdg_surface_set_add_id, | 
|  | xdg_surface_show_window_menu, | 
|  | xdg_surface_move, | 
|  | xdg_surface_resize, | 
|  | xdg_surface_ack_configure, | 
|  | xdg_surface_set_window_geometry, | 
|  | xdg_surface_set_maximized, | 
|  | xdg_surface_unset_maximized, | 
|  | xdg_surface_set_fullscreen, | 
|  | xdg_surface_unset_fullscreen, | 
|  | xdg_surface_set_minimized}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // xdg_shell_interface: | 
|  |  | 
|  | void xdg_shell_destroy(wl_client* client, wl_resource* resource) { | 
|  | // Nothing to do here. | 
|  | } | 
|  |  | 
|  | // Currently implemented version of the unstable xdg-shell interface. | 
|  | #define XDG_SHELL_VERSION 5 | 
|  | static_assert(XDG_SHELL_VERSION == XDG_SHELL_VERSION_CURRENT, | 
|  | "Interface version doesn't match implementation version"); | 
|  |  | 
|  | void xdg_shell_use_unstable_version(wl_client* client, | 
|  | wl_resource* resource, | 
|  | int32_t version) { | 
|  | if (version > XDG_SHELL_VERSION) { | 
|  | wl_resource_post_error(resource, 1, | 
|  | "xdg-shell version not implemented yet."); | 
|  | } | 
|  | } | 
|  |  | 
|  | void HandleXdgSurfaceConfigureCallback(wl_resource* resource, | 
|  | const gfx::Size& size) { | 
|  | // TODO(reveman): Include the shell surface state (maximized, active, etc.) | 
|  | // and make sure this configure callback is called when any of that state | 
|  | // changes. | 
|  | wl_array states; | 
|  | wl_array_init(&states); | 
|  | xdg_surface_send_configure(resource, size.width(), size.height(), &states, | 
|  | wl_display_next_serial(wl_client_get_display( | 
|  | wl_resource_get_client(resource)))); | 
|  | } | 
|  |  | 
|  | void xdg_shell_get_xdg_surface(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | wl_resource* surface) { | 
|  | scoped_ptr<ShellSurface> shell_surface = | 
|  | GetUserDataAs<Display>(resource) | 
|  | ->CreateShellSurface(GetUserDataAs<Surface>(surface)); | 
|  | if (!shell_surface) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource* xdg_surface_resource = | 
|  | wl_resource_create(client, &xdg_surface_interface, 1, id); | 
|  | if (!xdg_surface_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // An XdgSurface is a toplevel shell surface. | 
|  | shell_surface->Init(); | 
|  |  | 
|  | shell_surface->set_close_callback(base::Bind( | 
|  | &xdg_surface_send_close, base::Unretained(xdg_surface_resource))); | 
|  |  | 
|  | shell_surface->set_configure_callback( | 
|  | base::Bind(&HandleXdgSurfaceConfigureCallback, | 
|  | base::Unretained(xdg_surface_resource))); | 
|  |  | 
|  | SetImplementation(xdg_surface_resource, &xdg_surface_implementation, | 
|  | std::move(shell_surface)); | 
|  | } | 
|  |  | 
|  | void xdg_shell_get_xdg_popup(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | wl_resource* surface, | 
|  | wl_resource* parent, | 
|  | wl_resource* seat, | 
|  | uint32_t serial, | 
|  | int32_t x, | 
|  | int32_t y) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void xdg_shell_pong(wl_client* client, wl_resource* resource, uint32_t serial) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | const struct xdg_shell_interface xdg_shell_implementation = { | 
|  | xdg_shell_destroy, xdg_shell_use_unstable_version, | 
|  | xdg_shell_get_xdg_surface, xdg_shell_get_xdg_popup, xdg_shell_pong}; | 
|  |  | 
|  | void bind_xdg_shell(wl_client* client, | 
|  | void* data, | 
|  | uint32_t version, | 
|  | uint32_t id) { | 
|  | wl_resource* resource = | 
|  | wl_resource_create(client, &xdg_shell_interface, 1, id); | 
|  | if (!resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  | wl_resource_set_implementation(resource, &xdg_shell_implementation, data, | 
|  | nullptr); | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_data_device_interface: | 
|  |  | 
|  | void data_device_start_drag(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* source_resource, | 
|  | wl_resource* origin_resource, | 
|  | wl_resource* icon_resource, | 
|  | uint32_t serial) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void data_device_set_selection(wl_client* client, | 
|  | wl_resource* resource, | 
|  | wl_resource* data_source, | 
|  | uint32_t serial) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | const struct wl_data_device_interface data_device_implementation = { | 
|  | data_device_start_drag, data_device_set_selection}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_data_device_manager_interface: | 
|  |  | 
|  | void data_device_manager_create_data_source(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void data_device_manager_get_data_device(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t id, | 
|  | wl_resource* seat_resource) { | 
|  | wl_resource* data_device_resource = | 
|  | wl_resource_create(client, &wl_data_device_interface, 1, id); | 
|  | if (!data_device_resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource_set_implementation(data_device_resource, | 
|  | &data_device_implementation, nullptr, nullptr); | 
|  | } | 
|  |  | 
|  | const struct wl_data_device_manager_interface | 
|  | data_device_manager_implementation = { | 
|  | data_device_manager_create_data_source, | 
|  | data_device_manager_get_data_device}; | 
|  |  | 
|  | void bind_data_device_manager(wl_client* client, | 
|  | void* data, | 
|  | uint32_t version, | 
|  | uint32_t id) { | 
|  | wl_resource* resource = | 
|  | wl_resource_create(client, &wl_data_device_manager_interface, 1, id); | 
|  | if (!resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource_set_implementation(resource, &data_device_manager_implementation, | 
|  | data, nullptr); | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_pointer_interface: | 
|  |  | 
|  | // Pointer delegate class that accepts events for surfaces owned by the same | 
|  | // client as a pointer resource. | 
|  | class WaylandPointerDelegate : public PointerDelegate { | 
|  | public: | 
|  | explicit WaylandPointerDelegate(wl_resource* pointer_resource) | 
|  | : pointer_resource_(pointer_resource) {} | 
|  |  | 
|  | // Overridden from PointerDelegate: | 
|  | void OnPointerDestroying(Pointer* pointer) override { delete this; } | 
|  | bool CanAcceptPointerEventsForSurface(Surface* surface) const override { | 
|  | wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey); | 
|  | // We can accept events for this surface if the client is the same as the | 
|  | // pointer. | 
|  | return surface_resource && | 
|  | wl_resource_get_client(surface_resource) == client(); | 
|  | } | 
|  | void OnPointerEnter(Surface* surface, | 
|  | const gfx::Point& location, | 
|  | int button_flags) override { | 
|  | wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey); | 
|  | DCHECK(surface_resource); | 
|  | // Should we be sending button events to the client before the enter event | 
|  | // if client's pressed button state is different from |button_flags|? | 
|  | wl_pointer_send_enter(pointer_resource_, next_serial(), surface_resource, | 
|  | wl_fixed_from_int(location.x()), | 
|  | wl_fixed_from_int(location.y())); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnPointerLeave(Surface* surface) override { | 
|  | wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey); | 
|  | DCHECK(surface_resource); | 
|  | wl_pointer_send_leave(pointer_resource_, next_serial(), surface_resource); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnPointerMotion(base::TimeDelta time_stamp, | 
|  | const gfx::Point& location) override { | 
|  | wl_pointer_send_motion(pointer_resource_, time_stamp.InMilliseconds(), | 
|  | wl_fixed_from_int(location.x()), | 
|  | wl_fixed_from_int(location.y())); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnPointerButton(base::TimeDelta time_stamp, | 
|  | int button_flags, | 
|  | bool pressed) override { | 
|  | struct { | 
|  | ui::EventFlags flag; | 
|  | uint32_t value; | 
|  | } buttons[] = { | 
|  | {ui::EF_LEFT_MOUSE_BUTTON, BTN_LEFT}, | 
|  | {ui::EF_RIGHT_MOUSE_BUTTON, BTN_RIGHT}, | 
|  | {ui::EF_MIDDLE_MOUSE_BUTTON, BTN_MIDDLE}, | 
|  | {ui::EF_FORWARD_MOUSE_BUTTON, BTN_FORWARD}, | 
|  | {ui::EF_BACK_MOUSE_BUTTON, BTN_BACK}, | 
|  | }; | 
|  | uint32_t serial = next_serial(); | 
|  | for (auto button : buttons) { | 
|  | if (button_flags & button.flag) { | 
|  | wl_pointer_send_button(pointer_resource_, serial, | 
|  | time_stamp.InMilliseconds(), button.value, | 
|  | pressed ? WL_POINTER_BUTTON_STATE_PRESSED | 
|  | : WL_POINTER_BUTTON_STATE_RELEASED); | 
|  | } | 
|  | } | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnPointerWheel(base::TimeDelta time_stamp, | 
|  | const gfx::Vector2d& offset) override { | 
|  | // Same as Weston, the reference compositor. | 
|  | const double kAxisStepDistance = 10.0 / ui::MouseWheelEvent::kWheelDelta; | 
|  |  | 
|  | double x_value = offset.x() * kAxisStepDistance; | 
|  | if (x_value) { | 
|  | wl_pointer_send_axis(pointer_resource_, time_stamp.InMilliseconds(), | 
|  | WL_POINTER_AXIS_HORIZONTAL_SCROLL, | 
|  | wl_fixed_from_double(-x_value)); | 
|  | } | 
|  | double y_value = offset.y() * kAxisStepDistance; | 
|  | if (y_value) { | 
|  | wl_pointer_send_axis(pointer_resource_, time_stamp.InMilliseconds(), | 
|  | WL_POINTER_AXIS_VERTICAL_SCROLL, | 
|  | wl_fixed_from_double(-y_value)); | 
|  | } | 
|  | wl_client_flush(client()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // The client who own this pointer instance. | 
|  | wl_client* client() const { | 
|  | return wl_resource_get_client(pointer_resource_); | 
|  | } | 
|  |  | 
|  | // Returns the next serial to use for pointer events. | 
|  | uint32_t next_serial() const { | 
|  | return wl_display_next_serial(wl_client_get_display(client())); | 
|  | } | 
|  |  | 
|  | // The pointer resource associated with the pointer. | 
|  | wl_resource* const pointer_resource_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(WaylandPointerDelegate); | 
|  | }; | 
|  |  | 
|  | void pointer_set_cursor(wl_client* client, | 
|  | wl_resource* resource, | 
|  | uint32_t serial, | 
|  | wl_resource* surface_resource, | 
|  | int32_t hotspot_x, | 
|  | int32_t hotspot_y) { | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | void pointer_release(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | const struct wl_pointer_interface pointer_implementation = {pointer_set_cursor, | 
|  | pointer_release}; | 
|  |  | 
|  | #if defined(USE_XKBCOMMON) | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_keyboard_interface: | 
|  |  | 
|  | // Keyboard delegate class that accepts events for surfaces owned by the same | 
|  | // client as a keyboard resource. | 
|  | class WaylandKeyboardDelegate : public KeyboardDelegate { | 
|  | public: | 
|  | explicit WaylandKeyboardDelegate(wl_resource* keyboard_resource) | 
|  | : keyboard_resource_(keyboard_resource), | 
|  | xkb_context_(xkb_context_new(XKB_CONTEXT_NO_FLAGS)), | 
|  | // TODO(reveman): Keep keymap synchronized with the keymap used by | 
|  | // chromium and the host OS. | 
|  | xkb_keymap_(xkb_keymap_new_from_names(xkb_context_.get(), | 
|  | nullptr, | 
|  | XKB_KEYMAP_COMPILE_NO_FLAGS)), | 
|  | xkb_state_(xkb_state_new(xkb_keymap_.get())) { | 
|  | scoped_ptr<char, base::FreeDeleter> keymap_string( | 
|  | xkb_keymap_get_as_string(xkb_keymap_.get(), XKB_KEYMAP_FORMAT_TEXT_V1)); | 
|  | DCHECK(keymap_string.get()); | 
|  | size_t keymap_size = strlen(keymap_string.get()) + 1; | 
|  | base::SharedMemory shared_keymap; | 
|  | bool rv = shared_keymap.CreateAndMapAnonymous(keymap_size); | 
|  | DCHECK(rv); | 
|  | memcpy(shared_keymap.memory(), keymap_string.get(), keymap_size); | 
|  | wl_keyboard_send_keymap(keyboard_resource_, | 
|  | WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, | 
|  | shared_keymap.handle().fd, keymap_size); | 
|  | } | 
|  |  | 
|  | // Overridden from KeyboardDelegate: | 
|  | void OnKeyboardDestroying(Keyboard* keyboard) override { delete this; } | 
|  | bool CanAcceptKeyboardEventsForSurface(Surface* surface) const override { | 
|  | wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey); | 
|  | // We can accept events for this surface if the client is the same as the | 
|  | // keyboard. | 
|  | return surface_resource && | 
|  | wl_resource_get_client(surface_resource) == client(); | 
|  | } | 
|  | void OnKeyboardEnter(Surface* surface, | 
|  | const std::vector<ui::DomCode>& pressed_keys) override { | 
|  | wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey); | 
|  | DCHECK(surface_resource); | 
|  | wl_array keys; | 
|  | wl_array_init(&keys); | 
|  | for (auto key : pressed_keys) { | 
|  | uint32_t* value = | 
|  | static_cast<uint32_t*>(wl_array_add(&keys, sizeof(uint32_t))); | 
|  | DCHECK(value); | 
|  | *value = DomCodeToKey(key); | 
|  | } | 
|  | wl_keyboard_send_enter(keyboard_resource_, next_serial(), surface_resource, | 
|  | &keys); | 
|  | wl_array_release(&keys); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnKeyboardLeave(Surface* surface) override { | 
|  | wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey); | 
|  | DCHECK(surface_resource); | 
|  | wl_keyboard_send_leave(keyboard_resource_, next_serial(), surface_resource); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnKeyboardKey(base::TimeDelta time_stamp, | 
|  | ui::DomCode key, | 
|  | bool pressed) override { | 
|  | wl_keyboard_send_key(keyboard_resource_, next_serial(), | 
|  | time_stamp.InMilliseconds(), DomCodeToKey(key), | 
|  | pressed ? WL_KEYBOARD_KEY_STATE_PRESSED | 
|  | : WL_KEYBOARD_KEY_STATE_RELEASED); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnKeyboardModifiers(int modifier_flags) override { | 
|  | xkb_state_update_mask(xkb_state_.get(), | 
|  | ModifierFlagsToXkbModifiers(modifier_flags), 0, 0, 0, | 
|  | 0, 0); | 
|  | wl_keyboard_send_modifiers( | 
|  | keyboard_resource_, next_serial(), | 
|  | xkb_state_serialize_mods(xkb_state_.get(), XKB_STATE_MODS_DEPRESSED), | 
|  | xkb_state_serialize_mods(xkb_state_.get(), XKB_STATE_MODS_LOCKED), | 
|  | xkb_state_serialize_mods(xkb_state_.get(), XKB_STATE_MODS_LATCHED), | 
|  | xkb_state_serialize_layout(xkb_state_.get(), | 
|  | XKB_STATE_LAYOUT_EFFECTIVE)); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // Returns the corresponding key given a dom code. | 
|  | uint32_t DomCodeToKey(ui::DomCode code) const { | 
|  | // This assumes KeycodeConverter has been built with evdev/xkb codes. | 
|  | xkb_keycode_t xkb_keycode = static_cast<xkb_keycode_t>( | 
|  | ui::KeycodeConverter::DomCodeToNativeKeycode(code)); | 
|  |  | 
|  | // Keycodes are offset by 8 in Xkb. | 
|  | DCHECK_GE(xkb_keycode, 8u); | 
|  | return xkb_keycode - 8; | 
|  | } | 
|  |  | 
|  | // Returns a set of Xkb modififers given a set of modifier flags. | 
|  | uint32_t ModifierFlagsToXkbModifiers(int modifier_flags) { | 
|  | struct { | 
|  | ui::EventFlags flag; | 
|  | const char* xkb_name; | 
|  | } modifiers[] = { | 
|  | {ui::EF_SHIFT_DOWN, XKB_MOD_NAME_SHIFT}, | 
|  | {ui::EF_CONTROL_DOWN, XKB_MOD_NAME_CTRL}, | 
|  | {ui::EF_ALT_DOWN, XKB_MOD_NAME_ALT}, | 
|  | {ui::EF_COMMAND_DOWN, XKB_MOD_NAME_LOGO}, | 
|  | {ui::EF_ALTGR_DOWN, "Mod5"}, | 
|  | {ui::EF_MOD3_DOWN, "Mod3"}, | 
|  | {ui::EF_NUM_LOCK_ON, XKB_MOD_NAME_NUM}, | 
|  | {ui::EF_CAPS_LOCK_ON, XKB_MOD_NAME_CAPS}, | 
|  | }; | 
|  | uint32_t xkb_modifiers = 0; | 
|  | for (auto modifier : modifiers) { | 
|  | if (modifier_flags & modifier.flag) { | 
|  | xkb_modifiers |= | 
|  | 1 << xkb_keymap_mod_get_index(xkb_keymap_.get(), modifier.xkb_name); | 
|  | } | 
|  | } | 
|  | return xkb_modifiers; | 
|  | } | 
|  |  | 
|  | // The client who own this keyboard instance. | 
|  | wl_client* client() const { | 
|  | return wl_resource_get_client(keyboard_resource_); | 
|  | } | 
|  |  | 
|  | // Returns the next serial to use for keyboard events. | 
|  | uint32_t next_serial() const { | 
|  | return wl_display_next_serial(wl_client_get_display(client())); | 
|  | } | 
|  |  | 
|  | // The keyboard resource associated with the keyboard. | 
|  | wl_resource* const keyboard_resource_; | 
|  |  | 
|  | // The Xkb state used for the keyboard. | 
|  | scoped_ptr<xkb_context, ui::XkbContextDeleter> xkb_context_; | 
|  | scoped_ptr<xkb_keymap, ui::XkbKeymapDeleter> xkb_keymap_; | 
|  | scoped_ptr<xkb_state, ui::XkbStateDeleter> xkb_state_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(WaylandKeyboardDelegate); | 
|  | }; | 
|  |  | 
|  | void keyboard_release(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | const struct wl_keyboard_interface keyboard_implementation = {keyboard_release}; | 
|  |  | 
|  | #endif | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_touch_interface: | 
|  |  | 
|  | // Touch delegate class that accepts events for surfaces owned by the same | 
|  | // client as a touch resource. | 
|  | class WaylandTouchDelegate : public TouchDelegate { | 
|  | public: | 
|  | explicit WaylandTouchDelegate(wl_resource* touch_resource) | 
|  | : touch_resource_(touch_resource) {} | 
|  |  | 
|  | // Overridden from TouchDelegate: | 
|  | void OnTouchDestroying(Touch* touch) override { delete this; } | 
|  | bool CanAcceptTouchEventsForSurface(Surface* surface) const override { | 
|  | wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey); | 
|  | // We can accept events for this surface if the client is the same as the | 
|  | // touch resource. | 
|  | return surface_resource && | 
|  | wl_resource_get_client(surface_resource) == client(); | 
|  | } | 
|  | void OnTouchDown(Surface* surface, | 
|  | base::TimeDelta time_stamp, | 
|  | int id, | 
|  | const gfx::Point& location) override { | 
|  | wl_resource* surface_resource = surface->GetProperty(kSurfaceResourceKey); | 
|  | DCHECK(surface_resource); | 
|  | wl_touch_send_down(touch_resource_, next_serial(), | 
|  | time_stamp.InMilliseconds(), surface_resource, id, | 
|  | wl_fixed_from_int(location.x()), | 
|  | wl_fixed_from_int(location.y())); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnTouchUp(base::TimeDelta time_stamp, int id) override { | 
|  | wl_touch_send_up(touch_resource_, next_serial(), | 
|  | time_stamp.InMilliseconds(), id); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnTouchMotion(base::TimeDelta time_stamp, | 
|  | int id, | 
|  | const gfx::Point& location) override { | 
|  | wl_touch_send_motion(touch_resource_, time_stamp.InMilliseconds(), id, | 
|  | wl_fixed_from_int(location.x()), | 
|  | wl_fixed_from_int(location.y())); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  | void OnTouchCancel() override { | 
|  | wl_touch_send_cancel(touch_resource_); | 
|  | wl_client_flush(client()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // The client who own this touch instance. | 
|  | wl_client* client() const { return wl_resource_get_client(touch_resource_); } | 
|  |  | 
|  | // Returns the next serial to use for keyboard events. | 
|  | uint32_t next_serial() const { | 
|  | return wl_display_next_serial(wl_client_get_display(client())); | 
|  | } | 
|  |  | 
|  | // The touch resource associated with the touch. | 
|  | wl_resource* const touch_resource_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(WaylandTouchDelegate); | 
|  | }; | 
|  |  | 
|  | void touch_release(wl_client* client, wl_resource* resource) { | 
|  | wl_resource_destroy(resource); | 
|  | } | 
|  |  | 
|  | const struct wl_touch_interface touch_implementation = {touch_release}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // wl_seat_interface: | 
|  |  | 
|  | void seat_get_pointer(wl_client* client, wl_resource* resource, uint32_t id) { | 
|  | wl_resource* pointer_resource = wl_resource_create( | 
|  | client, &wl_pointer_interface, wl_resource_get_version(resource), id); | 
|  | if (!pointer_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SetImplementation(pointer_resource, &pointer_implementation, | 
|  | make_scoped_ptr(new Pointer( | 
|  | new WaylandPointerDelegate(pointer_resource)))); | 
|  | } | 
|  |  | 
|  | void seat_get_keyboard(wl_client* client, wl_resource* resource, uint32_t id) { | 
|  | #if defined(USE_XKBCOMMON) | 
|  | uint32_t version = wl_resource_get_version(resource); | 
|  | wl_resource* keyboard_resource = | 
|  | wl_resource_create(client, &wl_keyboard_interface, version, id); | 
|  | if (!keyboard_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SetImplementation(keyboard_resource, &keyboard_implementation, | 
|  | make_scoped_ptr(new Keyboard( | 
|  | new WaylandKeyboardDelegate(keyboard_resource)))); | 
|  |  | 
|  | // TODO(reveman): Keep repeat info synchronized with chromium and the host OS. | 
|  | if (version >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) | 
|  | wl_keyboard_send_repeat_info(keyboard_resource, 40, 500); | 
|  | #else | 
|  | NOTIMPLEMENTED(); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void seat_get_touch(wl_client* client, wl_resource* resource, uint32_t id) { | 
|  | wl_resource* touch_resource = wl_resource_create( | 
|  | client, &wl_touch_interface, wl_resource_get_version(resource), id); | 
|  | if (!touch_resource) { | 
|  | wl_resource_post_no_memory(resource); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SetImplementation( | 
|  | touch_resource, &touch_implementation, | 
|  | make_scoped_ptr(new Touch(new WaylandTouchDelegate(touch_resource)))); | 
|  | } | 
|  |  | 
|  | const struct wl_seat_interface seat_implementation = { | 
|  | seat_get_pointer, seat_get_keyboard, seat_get_touch}; | 
|  |  | 
|  | const uint32_t seat_version = 4; | 
|  |  | 
|  | void bind_seat(wl_client* client, void* data, uint32_t version, uint32_t id) { | 
|  | wl_resource* resource = wl_resource_create( | 
|  | client, &wl_seat_interface, std::min(version, seat_version), id); | 
|  | if (!resource) { | 
|  | wl_client_post_no_memory(client); | 
|  | return; | 
|  | } | 
|  |  | 
|  | wl_resource_set_implementation(resource, &seat_implementation, data, nullptr); | 
|  |  | 
|  | if (version >= WL_SEAT_NAME_SINCE_VERSION) | 
|  | wl_seat_send_name(resource, "default"); | 
|  |  | 
|  | uint32_t capabilities = WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH; | 
|  | #if defined(USE_XKBCOMMON) | 
|  | capabilities |= WL_SEAT_CAPABILITY_KEYBOARD; | 
|  | #endif | 
|  | wl_seat_send_capabilities(resource, capabilities); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // Server, public: | 
|  |  | 
|  | Server::Server(Display* display) | 
|  | : display_(display), wl_display_(wl_display_create()) { | 
|  | wl_global_create(wl_display_.get(), &wl_compositor_interface, | 
|  | compositor_version, display_, bind_compositor); | 
|  | wl_global_create(wl_display_.get(), &wl_shm_interface, 1, display_, bind_shm); | 
|  | #if defined(USE_OZONE) | 
|  | wl_global_create(wl_display_.get(), &wl_drm_interface, drm_version, display_, | 
|  | bind_drm); | 
|  | #endif | 
|  | wl_global_create(wl_display_.get(), &wl_subcompositor_interface, 1, display_, | 
|  | bind_subcompositor); | 
|  | wl_global_create(wl_display_.get(), &wl_shell_interface, 1, display_, | 
|  | bind_shell); | 
|  | wl_global_create(wl_display_.get(), &wl_output_interface, output_version, | 
|  | display_, bind_output); | 
|  | wl_global_create(wl_display_.get(), &xdg_shell_interface, 1, display_, | 
|  | bind_xdg_shell); | 
|  | wl_global_create(wl_display_.get(), &wl_data_device_manager_interface, 1, | 
|  | display_, bind_data_device_manager); | 
|  | wl_global_create(wl_display_.get(), &wl_seat_interface, seat_version, | 
|  | display_, bind_seat); | 
|  | } | 
|  |  | 
|  | Server::~Server() {} | 
|  |  | 
|  | // static | 
|  | scoped_ptr<Server> Server::Create(Display* display) { | 
|  | scoped_ptr<Server> server(new Server(display)); | 
|  | int rv = wl_display_add_socket(server->wl_display_.get(), nullptr); | 
|  | DCHECK_EQ(rv, 0) << "wl_display_add_socket failed: " << rv; | 
|  | return server; | 
|  | } | 
|  |  | 
|  | bool Server::AddSocket(const std::string name) { | 
|  | DCHECK(!name.empty()); | 
|  | return !wl_display_add_socket(wl_display_.get(), name.c_str()); | 
|  | } | 
|  |  | 
|  | int Server::GetFileDescriptor() const { | 
|  | wl_event_loop* event_loop = wl_display_get_event_loop(wl_display_.get()); | 
|  | DCHECK(event_loop); | 
|  | return wl_event_loop_get_fd(event_loop); | 
|  | } | 
|  |  | 
|  | void Server::Dispatch(base::TimeDelta timeout) { | 
|  | wl_event_loop* event_loop = wl_display_get_event_loop(wl_display_.get()); | 
|  | DCHECK(event_loop); | 
|  | wl_event_loop_dispatch(event_loop, timeout.InMilliseconds()); | 
|  | } | 
|  |  | 
|  | void Server::Flush() { | 
|  | wl_display_flush_clients(wl_display_.get()); | 
|  | } | 
|  |  | 
|  | }  // namespace wayland | 
|  | }  // namespace exo |