OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <fcntl.h> |
| 6 #include <string.h> |
| 7 #include <unistd.h> |
| 8 #include <wayland-client.h> |
| 9 |
| 10 #include <memory> |
| 11 #include <sys/mman.h> |
| 12 |
| 13 namespace { |
| 14 |
| 15 class WaylandClient { |
| 16 public: |
| 17 static WaylandClient* Create() { |
| 18 std::unique_ptr<WaylandClient> client(new WaylandClient); |
| 19 if (client->Initialize()) |
| 20 return client.release(); |
| 21 return nullptr; |
| 22 } |
| 23 |
| 24 ~WaylandClient() { |
| 25 wl_pointer_destroy(pointer_); |
| 26 wl_seat_destroy(seat_); |
| 27 wl_shell_destroy(shell_); |
| 28 wl_shm_destroy(shm_); |
| 29 wl_compositor_destroy(compositor_); |
| 30 wl_display_disconnect(display_); |
| 31 } |
| 32 |
| 33 bool running() const { return running_; } |
| 34 struct wl_compositor* compositor() const { |
| 35 return compositor_; |
| 36 } |
| 37 struct wl_display* display() const { |
| 38 return display_; |
| 39 } |
| 40 struct wl_shell* shell() const { |
| 41 return shell_; |
| 42 } |
| 43 struct wl_shm* shm() const { |
| 44 return shm_; |
| 45 } |
| 46 |
| 47 private: |
| 48 WaylandClient() {} |
| 49 WaylandClient(const WaylandClient&) = delete; |
| 50 void operator=(const WaylandClient&) = delete; |
| 51 |
| 52 bool Initialize() { |
| 53 display_ = wl_display_connect(nullptr); |
| 54 if (!display_) { |
| 55 perror("Cannot open display"); |
| 56 return false; |
| 57 } |
| 58 |
| 59 struct wl_registry* registry = wl_display_get_registry(display_); |
| 60 const struct wl_registry_listener registry_listener = { |
| 61 WaylandClient::OnRegistry, WaylandClient::OnRemoveRegistry}; |
| 62 wl_registry_add_listener(registry, ®istry_listener, this); |
| 63 wl_display_roundtrip(display_); |
| 64 wl_registry_destroy(registry); |
| 65 running_ = true; |
| 66 |
| 67 return true; |
| 68 } |
| 69 |
| 70 static void OnRemoveRegistry(void* a, struct wl_registry* b, uint32_t c) {} |
| 71 |
| 72 static void OnRegistry(void* data, |
| 73 struct wl_registry* registry, |
| 74 uint32_t name, |
| 75 const char* interface, |
| 76 uint32_t version) { |
| 77 WaylandClient* me = static_cast<WaylandClient*>(data); |
| 78 if (!strcmp(interface, wl_compositor_interface.name)) { |
| 79 me->compositor_ = static_cast<wl_compositor*>( |
| 80 wl_registry_bind(registry, name, &wl_compositor_interface, version)); |
| 81 } else if (!strcmp(interface, wl_shm_interface.name)) { |
| 82 me->shm_ = static_cast<wl_shm*>( |
| 83 wl_registry_bind(registry, name, &wl_shm_interface, version)); |
| 84 } else if (!strcmp(interface, wl_shell_interface.name)) { |
| 85 me->shell_ = static_cast<wl_shell*>( |
| 86 wl_registry_bind(registry, name, &wl_shell_interface, version)); |
| 87 } else if (!strcmp(interface, wl_seat_interface.name)) { |
| 88 me->seat_ = static_cast<wl_seat*>( |
| 89 wl_registry_bind(registry, name, &wl_seat_interface, version)); |
| 90 me->pointer_ = wl_seat_get_pointer(me->seat_); |
| 91 const struct wl_pointer_listener pointer_listener = { |
| 92 OnPointerEnter, OnPointerLeave, OnPointerMotion, OnPointerButton, |
| 93 OnPointerAxis}; |
| 94 wl_pointer_add_listener(me->pointer_, &pointer_listener, data); |
| 95 } |
| 96 } |
| 97 |
| 98 static void OnPointerEnter(void* data, |
| 99 struct wl_pointer* wl_pointer, |
| 100 uint32_t serial, |
| 101 struct wl_surface* surface, |
| 102 wl_fixed_t surface_x, |
| 103 wl_fixed_t surface_y) {} |
| 104 static void OnPointerLeave(void* data, |
| 105 struct wl_pointer* wl_pointer, |
| 106 uint32_t serial, |
| 107 struct wl_surface* wl_surface) {} |
| 108 |
| 109 static void OnPointerMotion(void* data, |
| 110 struct wl_pointer* wl_pointer, |
| 111 uint32_t time, |
| 112 wl_fixed_t surface_x, |
| 113 wl_fixed_t surface_y) {} |
| 114 |
| 115 // Program exits if clicking any mouse buttons. |
| 116 static void OnPointerButton(void* data, |
| 117 struct wl_pointer* wl_pointer, |
| 118 uint32_t serial, |
| 119 uint32_t time, |
| 120 uint32_t button, |
| 121 uint32_t state) { |
| 122 WaylandClient* me = static_cast<WaylandClient*>(data); |
| 123 me->running_ = false; |
| 124 } |
| 125 |
| 126 static void OnPointerAxis(void* data, |
| 127 struct wl_pointer* wl_pointer, |
| 128 uint32_t time, |
| 129 uint32_t axis, |
| 130 wl_fixed_t value) {} |
| 131 |
| 132 bool running_ = false; |
| 133 struct wl_compositor* compositor_ = nullptr; |
| 134 struct wl_display* display_ = nullptr; |
| 135 struct wl_pointer* pointer_ = nullptr; |
| 136 struct wl_seat* seat_ = nullptr; |
| 137 struct wl_shell* shell_ = nullptr; |
| 138 struct wl_shm* shm_ = nullptr; |
| 139 }; |
| 140 |
| 141 class DemoWindow { |
| 142 public: |
| 143 DemoWindow() {} |
| 144 ~DemoWindow() { |
| 145 wl_buffer_destroy(buffer_); |
| 146 wl_shell_surface_destroy(shell_surface_); |
| 147 wl_surface_destroy(surface_); |
| 148 } |
| 149 |
| 150 int Run() { |
| 151 client_.reset(WaylandClient::Create()); |
| 152 if (!client_) { |
| 153 perror("Cannot create WaylandClient"); |
| 154 return EXIT_FAILURE; |
| 155 } |
| 156 |
| 157 if (!CreateBuffer()) { |
| 158 perror("Creating a buffer failed"); |
| 159 return EXIT_FAILURE; |
| 160 } |
| 161 |
| 162 if (!CreateSurface()) { |
| 163 perror("Creating a surface failed"); |
| 164 return EXIT_FAILURE; |
| 165 } |
| 166 |
| 167 Redraw(this, nullptr, 0); |
| 168 int ret = 0; |
| 169 while (client_->running() && ret != -1) |
| 170 ret = wl_display_dispatch(client_->display()); |
| 171 |
| 172 return EXIT_SUCCESS; |
| 173 } |
| 174 |
| 175 private: |
| 176 DemoWindow(const DemoWindow&) = delete; |
| 177 void operator=(const DemoWindow&) = delete; |
| 178 |
| 179 bool CreateBuffer() { |
| 180 int stride = WIDTH * 4; |
| 181 int size = stride * HEIGHT; |
| 182 ScopedFD fd(CreateAnonymousFile(size)); |
| 183 if (fd.Get() < 0) { |
| 184 perror("Creating a buffer file failed"); |
| 185 return false; |
| 186 } |
| 187 data_ = |
| 188 mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.Get(), 0); |
| 189 if (data_ == MAP_FAILED) { |
| 190 perror("mmap failed"); |
| 191 return false; |
| 192 } |
| 193 |
| 194 struct wl_shm_pool* pool = |
| 195 wl_shm_create_pool(client_->shm(), fd.Get(), size); |
| 196 buffer_ = wl_shm_pool_create_buffer(pool, 0, WIDTH, HEIGHT, stride, |
| 197 WL_SHM_FORMAT_XRGB8888); |
| 198 wl_shm_pool_destroy(pool); |
| 199 return true; |
| 200 } |
| 201 |
| 202 class ScopedFD { |
| 203 public: |
| 204 explicit ScopedFD(int fd) : fd_(fd) {} |
| 205 ~ScopedFD() { |
| 206 if (auto_close_) |
| 207 close(fd_); |
| 208 } |
| 209 int Get() { return fd_; } |
| 210 int Release() { |
| 211 auto_close_ = false; |
| 212 return fd_; |
| 213 } |
| 214 |
| 215 private: |
| 216 ScopedFD(const ScopedFD&) = delete; |
| 217 void operator=(const ScopedFD&) = delete; |
| 218 |
| 219 const int fd_; |
| 220 bool auto_close_ = true; |
| 221 }; |
| 222 |
| 223 int CreateAnonymousFile(off_t size) { |
| 224 static const std::string file_name = "/weston-shared-XXXXXX"; |
| 225 const std::string path = getenv("XDG_RUNTIME_DIR"); |
| 226 if (path.empty()) { |
| 227 errno = ENOENT; |
| 228 return -1; |
| 229 } |
| 230 |
| 231 std::string name = path + file_name; |
| 232 char* c_name = const_cast<char*>(name.data()); |
| 233 ScopedFD fd(mkstemp(c_name)); |
| 234 if (fd.Get() < 0) |
| 235 return -1; |
| 236 |
| 237 long flags = fcntl(fd.Get(), F_GETFD); |
| 238 if (flags == -1) |
| 239 return -1; |
| 240 if (fcntl(fd.Get(), F_SETFD, flags | FD_CLOEXEC) == -1) |
| 241 return -1; |
| 242 if (ftruncate(fd.Get(), size) < 0) |
| 243 return -1; |
| 244 |
| 245 return fd.Release(); |
| 246 } |
| 247 |
| 248 bool CreateSurface() { |
| 249 surface_ = wl_compositor_create_surface(client_->compositor()); |
| 250 if (!surface_) |
| 251 return false; |
| 252 |
| 253 shell_surface_ = wl_shell_get_shell_surface(client_->shell(), surface_); |
| 254 if (!shell_surface_) { |
| 255 wl_surface_destroy(surface_); |
| 256 return false; |
| 257 } |
| 258 |
| 259 wl_shell_surface_set_toplevel(shell_surface_); |
| 260 wl_shell_surface_set_user_data(shell_surface_, surface_); |
| 261 wl_surface_set_user_data(surface_, nullptr); |
| 262 return true; |
| 263 } |
| 264 |
| 265 static void Redraw(void* data, struct wl_callback* callback, uint32_t time) { |
| 266 DemoWindow* me = static_cast<DemoWindow*>(data); |
| 267 |
| 268 PaintPixels(me->data_, 20, WIDTH, HEIGHT, time); |
| 269 |
| 270 const int border_width = 20; |
| 271 wl_surface_attach(me->surface_, me->buffer_, 0, 0); |
| 272 wl_surface_damage(me->surface_, border_width, border_width, |
| 273 WIDTH - 2 * border_width, HEIGHT - 2 * border_width); |
| 274 if (callback) |
| 275 wl_callback_destroy(callback); |
| 276 me->callback_ = wl_surface_frame(me->surface_); |
| 277 const struct wl_callback_listener frame_listener = {Redraw}; |
| 278 wl_callback_add_listener(me->callback_, &frame_listener, me); |
| 279 wl_surface_commit(me->surface_); |
| 280 } |
| 281 |
| 282 // Copied from |
| 283 // https://cgit.freedesktop.org/wayland/weston/tree/clients/simple-shm.c |
| 284 // which is in MIT license. |
| 285 static void PaintPixels(void* image, |
| 286 int padding, |
| 287 int width, |
| 288 int height, |
| 289 uint32_t time) { |
| 290 uint32_t* pixel = static_cast<uint32_t*>(image); |
| 291 const int halfh = padding + (height - padding * 2) / 2; |
| 292 const int halfw = padding + (width - padding * 2) / 2; |
| 293 |
| 294 /* squared radii thresholds */ |
| 295 int outr = (halfw < halfh ? halfw : halfh) - 8; |
| 296 int inr = outr - 32; |
| 297 outr *= outr; |
| 298 inr *= inr; |
| 299 |
| 300 pixel += padding * width; |
| 301 for (int y = padding; y < height - padding; y++) { |
| 302 int y2 = (y - halfh) * (y - halfh); |
| 303 pixel += padding; |
| 304 for (int x = padding; x < width - padding; x++) { |
| 305 uint32_t v; |
| 306 |
| 307 /* squared distance from center */ |
| 308 int r2 = (x - halfw) * (x - halfw) + y2; |
| 309 |
| 310 if (r2 < inr) |
| 311 v = (r2 / 32 + time / 64) * 0x0080401; |
| 312 else if (r2 < outr) |
| 313 v = (y + time / 32) * 0x0080401; |
| 314 else |
| 315 v = (x + time / 16) * 0x0080401; |
| 316 v &= 0x00ffffff; |
| 317 |
| 318 /* cross if compositor uses X from XRGB as alpha */ |
| 319 if (abs(x - y) > 6 && abs(x + y - height) > 6) |
| 320 v |= 0xff000000; |
| 321 |
| 322 *pixel++ = v; |
| 323 } |
| 324 |
| 325 pixel += padding; |
| 326 } |
| 327 } |
| 328 |
| 329 static const unsigned WIDTH = 300; |
| 330 static const unsigned HEIGHT = 300; |
| 331 |
| 332 std::unique_ptr<WaylandClient> client_; |
| 333 struct wl_shell_surface* shell_surface_ = nullptr; |
| 334 struct wl_surface* surface_ = nullptr; |
| 335 struct wl_buffer* buffer_ = nullptr; |
| 336 void* data_ = nullptr; |
| 337 struct wl_callback* callback_ = nullptr; |
| 338 }; |
| 339 |
| 340 } // namespace |
| 341 |
| 342 int main(int argc, char** argv) { |
| 343 std::unique_ptr<DemoWindow> window(new DemoWindow); |
| 344 return window->Run(); |
| 345 } |
OLD | NEW |