Index: components/exo/wayland/client_demo/wayland_client_demo.cc |
diff --git a/components/exo/wayland/client_demo/wayland_client_demo.cc b/components/exo/wayland/client_demo/wayland_client_demo.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..beeb01f3c4532456101d8a921bb1615dc2e21be9 |
--- /dev/null |
+++ b/components/exo/wayland/client_demo/wayland_client_demo.cc |
@@ -0,0 +1,345 @@ |
+// Copyright 2016 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 <fcntl.h> |
+#include <string.h> |
+#include <unistd.h> |
+#include <wayland-client.h> |
+ |
+#include <memory> |
+#include <sys/mman.h> |
+ |
+namespace { |
+ |
+class WaylandClient { |
+ public: |
+ static WaylandClient* Create() { |
+ std::unique_ptr<WaylandClient> client(new WaylandClient); |
+ if (client->Initialize()) |
+ return client.release(); |
+ return nullptr; |
+ } |
+ |
+ ~WaylandClient() { |
+ wl_pointer_destroy(pointer_); |
+ wl_seat_destroy(seat_); |
+ wl_shell_destroy(shell_); |
+ wl_shm_destroy(shm_); |
+ wl_compositor_destroy(compositor_); |
+ wl_display_disconnect(display_); |
+ } |
+ |
+ bool running() const { return running_; } |
+ struct wl_compositor* compositor() const { |
+ return compositor_; |
+ } |
+ struct wl_display* display() const { |
+ return display_; |
+ } |
+ struct wl_shell* shell() const { |
+ return shell_; |
+ } |
+ struct wl_shm* shm() const { |
+ return shm_; |
+ } |
+ |
+ private: |
+ WaylandClient() {} |
+ WaylandClient(const WaylandClient&) = delete; |
+ void operator=(const WaylandClient&) = delete; |
+ |
+ bool Initialize() { |
+ display_ = wl_display_connect(nullptr); |
+ if (!display_) { |
+ perror("Cannot open display"); |
+ return false; |
+ } |
+ |
+ struct wl_registry* registry = wl_display_get_registry(display_); |
+ const struct wl_registry_listener registry_listener = { |
+ WaylandClient::OnRegistry, WaylandClient::OnRemoveRegistry}; |
+ wl_registry_add_listener(registry, ®istry_listener, this); |
+ wl_display_roundtrip(display_); |
+ wl_registry_destroy(registry); |
+ running_ = true; |
+ |
+ return true; |
+ } |
+ |
+ static void OnRemoveRegistry(void* a, struct wl_registry* b, uint32_t c) {} |
+ |
+ static void OnRegistry(void* data, |
+ struct wl_registry* registry, |
+ uint32_t name, |
+ const char* interface, |
+ uint32_t version) { |
+ WaylandClient* me = static_cast<WaylandClient*>(data); |
+ if (!strcmp(interface, wl_compositor_interface.name)) { |
+ me->compositor_ = static_cast<wl_compositor*>( |
+ wl_registry_bind(registry, name, &wl_compositor_interface, version)); |
+ } else if (!strcmp(interface, wl_shm_interface.name)) { |
+ me->shm_ = static_cast<wl_shm*>( |
+ wl_registry_bind(registry, name, &wl_shm_interface, version)); |
+ } else if (!strcmp(interface, wl_shell_interface.name)) { |
+ me->shell_ = static_cast<wl_shell*>( |
+ wl_registry_bind(registry, name, &wl_shell_interface, version)); |
+ } else if (!strcmp(interface, wl_seat_interface.name)) { |
+ me->seat_ = static_cast<wl_seat*>( |
+ wl_registry_bind(registry, name, &wl_seat_interface, version)); |
+ me->pointer_ = wl_seat_get_pointer(me->seat_); |
+ const struct wl_pointer_listener pointer_listener = { |
+ OnPointerEnter, OnPointerLeave, OnPointerMotion, OnPointerButton, |
+ OnPointerAxis}; |
+ wl_pointer_add_listener(me->pointer_, &pointer_listener, data); |
+ } |
+ } |
+ |
+ static void OnPointerEnter(void* data, |
+ struct wl_pointer* wl_pointer, |
+ uint32_t serial, |
+ struct wl_surface* surface, |
+ wl_fixed_t surface_x, |
+ wl_fixed_t surface_y) {} |
+ static void OnPointerLeave(void* data, |
+ struct wl_pointer* wl_pointer, |
+ uint32_t serial, |
+ struct wl_surface* wl_surface) {} |
+ |
+ static void OnPointerMotion(void* data, |
+ struct wl_pointer* wl_pointer, |
+ uint32_t time, |
+ wl_fixed_t surface_x, |
+ wl_fixed_t surface_y) {} |
+ |
+ // Program exits if clicking any mouse buttons. |
+ static void OnPointerButton(void* data, |
+ struct wl_pointer* wl_pointer, |
+ uint32_t serial, |
+ uint32_t time, |
+ uint32_t button, |
+ uint32_t state) { |
+ WaylandClient* me = static_cast<WaylandClient*>(data); |
+ me->running_ = false; |
+ } |
+ |
+ static void OnPointerAxis(void* data, |
+ struct wl_pointer* wl_pointer, |
+ uint32_t time, |
+ uint32_t axis, |
+ wl_fixed_t value) {} |
+ |
+ bool running_ = false; |
+ struct wl_compositor* compositor_ = nullptr; |
+ struct wl_display* display_ = nullptr; |
+ struct wl_pointer* pointer_ = nullptr; |
+ struct wl_seat* seat_ = nullptr; |
+ struct wl_shell* shell_ = nullptr; |
+ struct wl_shm* shm_ = nullptr; |
+}; |
+ |
+class DemoWindow { |
+ public: |
+ DemoWindow() {} |
+ ~DemoWindow() { |
+ wl_buffer_destroy(buffer_); |
+ wl_shell_surface_destroy(shell_surface_); |
+ wl_surface_destroy(surface_); |
+ } |
+ |
+ int Run() { |
+ client_.reset(WaylandClient::Create()); |
+ if (!client_) { |
+ perror("Cannot create WaylandClient"); |
+ return EXIT_FAILURE; |
+ } |
+ |
+ if (!CreateBuffer()) { |
+ perror("Creating a buffer failed"); |
+ return EXIT_FAILURE; |
+ } |
+ |
+ if (!CreateSurface()) { |
+ perror("Creating a surface failed"); |
+ return EXIT_FAILURE; |
+ } |
+ |
+ Redraw(this, nullptr, 0); |
+ int ret = 0; |
+ while (client_->running() && ret != -1) |
+ ret = wl_display_dispatch(client_->display()); |
+ |
+ return EXIT_SUCCESS; |
+ } |
+ |
+ private: |
+ DemoWindow(const DemoWindow&) = delete; |
+ void operator=(const DemoWindow&) = delete; |
+ |
+ bool CreateBuffer() { |
+ int stride = WIDTH * 4; |
+ int size = stride * HEIGHT; |
+ ScopedFD fd(CreateAnonymousFile(size)); |
+ if (fd.Get() < 0) { |
+ perror("Creating a buffer file failed"); |
+ return false; |
+ } |
+ data_ = |
+ mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.Get(), 0); |
+ if (data_ == MAP_FAILED) { |
+ perror("mmap failed"); |
+ return false; |
+ } |
+ |
+ struct wl_shm_pool* pool = |
+ wl_shm_create_pool(client_->shm(), fd.Get(), size); |
+ buffer_ = wl_shm_pool_create_buffer(pool, 0, WIDTH, HEIGHT, stride, |
+ WL_SHM_FORMAT_XRGB8888); |
+ wl_shm_pool_destroy(pool); |
+ return true; |
+ } |
+ |
+ class ScopedFD { |
+ public: |
+ explicit ScopedFD(int fd) : fd_(fd) {} |
+ ~ScopedFD() { |
+ if (auto_close_) |
+ close(fd_); |
+ } |
+ int Get() { return fd_; } |
+ int Release() { |
+ auto_close_ = false; |
+ return fd_; |
+ } |
+ |
+ private: |
+ ScopedFD(const ScopedFD&) = delete; |
+ void operator=(const ScopedFD&) = delete; |
+ |
+ const int fd_; |
+ bool auto_close_ = true; |
+ }; |
+ |
+ int CreateAnonymousFile(off_t size) { |
+ static const std::string file_name = "/weston-shared-XXXXXX"; |
+ const std::string path = getenv("XDG_RUNTIME_DIR"); |
+ if (path.empty()) { |
+ errno = ENOENT; |
+ return -1; |
+ } |
+ |
+ std::string name = path + file_name; |
+ char* c_name = const_cast<char*>(name.data()); |
+ ScopedFD fd(mkstemp(c_name)); |
+ if (fd.Get() < 0) |
+ return -1; |
+ |
+ long flags = fcntl(fd.Get(), F_GETFD); |
+ if (flags == -1) |
+ return -1; |
+ if (fcntl(fd.Get(), F_SETFD, flags | FD_CLOEXEC) == -1) |
+ return -1; |
+ if (ftruncate(fd.Get(), size) < 0) |
+ return -1; |
+ |
+ return fd.Release(); |
+ } |
+ |
+ bool CreateSurface() { |
+ surface_ = wl_compositor_create_surface(client_->compositor()); |
+ if (!surface_) |
+ return false; |
+ |
+ shell_surface_ = wl_shell_get_shell_surface(client_->shell(), surface_); |
+ if (!shell_surface_) { |
+ wl_surface_destroy(surface_); |
+ return false; |
+ } |
+ |
+ wl_shell_surface_set_toplevel(shell_surface_); |
+ wl_shell_surface_set_user_data(shell_surface_, surface_); |
+ wl_surface_set_user_data(surface_, nullptr); |
+ return true; |
+ } |
+ |
+ static void Redraw(void* data, struct wl_callback* callback, uint32_t time) { |
+ DemoWindow* me = static_cast<DemoWindow*>(data); |
+ |
+ PaintPixels(me->data_, 20, WIDTH, HEIGHT, time); |
+ |
+ const int border_width = 20; |
+ wl_surface_attach(me->surface_, me->buffer_, 0, 0); |
+ wl_surface_damage(me->surface_, border_width, border_width, |
+ WIDTH - 2 * border_width, HEIGHT - 2 * border_width); |
+ if (callback) |
+ wl_callback_destroy(callback); |
+ me->callback_ = wl_surface_frame(me->surface_); |
+ const struct wl_callback_listener frame_listener = {Redraw}; |
+ wl_callback_add_listener(me->callback_, &frame_listener, me); |
+ wl_surface_commit(me->surface_); |
+ } |
+ |
+ // Copied from |
+ // https://cgit.freedesktop.org/wayland/weston/tree/clients/simple-shm.c |
+ // which is in MIT license. |
+ static void PaintPixels(void* image, |
+ int padding, |
+ int width, |
+ int height, |
+ uint32_t time) { |
+ uint32_t* pixel = static_cast<uint32_t*>(image); |
+ const int halfh = padding + (height - padding * 2) / 2; |
+ const int halfw = padding + (width - padding * 2) / 2; |
+ |
+ /* squared radii thresholds */ |
+ int outr = (halfw < halfh ? halfw : halfh) - 8; |
+ int inr = outr - 32; |
+ outr *= outr; |
+ inr *= inr; |
+ |
+ pixel += padding * width; |
+ for (int y = padding; y < height - padding; y++) { |
+ int y2 = (y - halfh) * (y - halfh); |
+ pixel += padding; |
+ for (int x = padding; x < width - padding; x++) { |
+ uint32_t v; |
+ |
+ /* squared distance from center */ |
+ int r2 = (x - halfw) * (x - halfw) + y2; |
+ |
+ if (r2 < inr) |
+ v = (r2 / 32 + time / 64) * 0x0080401; |
+ else if (r2 < outr) |
+ v = (y + time / 32) * 0x0080401; |
+ else |
+ v = (x + time / 16) * 0x0080401; |
+ v &= 0x00ffffff; |
+ |
+ /* cross if compositor uses X from XRGB as alpha */ |
+ if (abs(x - y) > 6 && abs(x + y - height) > 6) |
+ v |= 0xff000000; |
+ |
+ *pixel++ = v; |
+ } |
+ |
+ pixel += padding; |
+ } |
+ } |
+ |
+ static const unsigned WIDTH = 300; |
+ static const unsigned HEIGHT = 300; |
+ |
+ std::unique_ptr<WaylandClient> client_; |
+ struct wl_shell_surface* shell_surface_ = nullptr; |
+ struct wl_surface* surface_ = nullptr; |
+ struct wl_buffer* buffer_ = nullptr; |
+ void* data_ = nullptr; |
+ struct wl_callback* callback_ = nullptr; |
+}; |
+ |
+} // namespace |
+ |
+int main(int argc, char** argv) { |
+ std::unique_ptr<DemoWindow> window(new DemoWindow); |
+ return window->Run(); |
+} |