| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Implementation of a client that produces output in the form of RGBA | 5 // Implementation of a client that produces output in the form of RGBA |
| 6 // buffers when receiving pointer/touch events. RGB contains the lower | 6 // buffers when receiving pointer/touch events. RGB contains the lower |
| 7 // 24 bits of the event timestamp and A is 0xff. | 7 // 24 bits of the event timestamp and A is 0xff. |
| 8 | 8 |
| 9 #include <wayland-client-core.h> | 9 #include <wayland-client-core.h> |
| 10 #include <wayland-client-protocol.h> | 10 #include <wayland-client-protocol.h> |
| 11 | 11 |
| 12 #include <vector> |
| 13 |
| 12 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/macros.h" |
| 13 #include "base/memory/shared_memory.h" | 16 #include "base/memory/shared_memory.h" |
| 14 #include "third_party/skia/include/core/SkCanvas.h" | 17 #include "third_party/skia/include/core/SkCanvas.h" |
| 15 #include "third_party/skia/include/core/SkRefCnt.h" | 18 #include "third_party/skia/include/core/SkRefCnt.h" |
| 16 #include "third_party/skia/include/core/SkSurface.h" | 19 #include "third_party/skia/include/core/SkSurface.h" |
| 17 | 20 |
| 18 // Convenient macro that is used to define default deleters for wayland object | 21 // Convenient macro that is used to define default deleters for wayland object |
| 19 // types allowing them to be used with std::unique_ptr. | 22 // types allowing them to be used with std::unique_ptr. |
| 20 #define DEFAULT_DELETER(TypeName, DeleteFunction) \ | 23 #define DEFAULT_DELETER(TypeName, DeleteFunction) \ |
| 21 namespace std { \ | 24 namespace std { \ |
| 22 template <> \ | 25 template <> \ |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 } else if (strcmp(interface, "wl_seat") == 0) { | 93 } else if (strcmp(interface, "wl_seat") == 0) { |
| 91 globals->seat.reset(static_cast<wl_seat*>( | 94 globals->seat.reset(static_cast<wl_seat*>( |
| 92 wl_registry_bind(registry, id, &wl_seat_interface, 5))); | 95 wl_registry_bind(registry, id, &wl_seat_interface, 5))); |
| 93 } | 96 } |
| 94 } | 97 } |
| 95 | 98 |
| 96 void RegistryRemover(void* data, wl_registry* registry, uint32_t id) { | 99 void RegistryRemover(void* data, wl_registry* registry, uint32_t id) { |
| 97 LOG(WARNING) << "Got a registry losing event for " << id; | 100 LOG(WARNING) << "Got a registry losing event for " << id; |
| 98 } | 101 } |
| 99 | 102 |
| 100 struct BufferState { | 103 struct Buffer { |
| 101 std::unique_ptr<wl_buffer> buffer; | 104 std::unique_ptr<wl_buffer> buffer; |
| 102 sk_sp<SkSurface> sk_surface; | 105 sk_sp<SkSurface> sk_surface; |
| 103 bool busy = false; | 106 bool busy = false; |
| 104 }; | 107 }; |
| 105 | 108 |
| 106 void BufferRelease(void* data, wl_buffer* buffer) { | 109 void BufferRelease(void* data, wl_buffer* /* buffer */) { |
| 107 BufferState* state = static_cast<BufferState*>(data); | 110 Buffer* buffer = static_cast<Buffer*>(data); |
| 108 | 111 |
| 109 state->busy = false; | 112 buffer->busy = false; |
| 110 } | 113 } |
| 111 | 114 |
| 112 struct MainLoopContext { | 115 using EventTimeStack = std::vector<uint32_t>; |
| 113 bool shutdown = false; | |
| 114 uint32_t last_event_time = 0; | |
| 115 bool frame_callback_pending = false; | |
| 116 double rotation = 0.0; | |
| 117 }; | |
| 118 | 116 |
| 119 void PointerEnter(void* data, | 117 void PointerEnter(void* data, |
| 120 wl_pointer* pointer, | 118 wl_pointer* pointer, |
| 121 uint32_t serial, | 119 uint32_t serial, |
| 122 wl_surface* surface, | 120 wl_surface* surface, |
| 123 wl_fixed_t x, | 121 wl_fixed_t x, |
| 124 wl_fixed_t y) {} | 122 wl_fixed_t y) {} |
| 125 | 123 |
| 126 void PointerLeave(void* data, | 124 void PointerLeave(void* data, |
| 127 wl_pointer* pointer, | 125 wl_pointer* pointer, |
| 128 uint32_t serial, | 126 uint32_t serial, |
| 129 wl_surface* surface) {} | 127 wl_surface* surface) {} |
| 130 | 128 |
| 131 void PointerMotion(void* data, | 129 void PointerMotion(void* data, |
| 132 wl_pointer* pointer, | 130 wl_pointer* pointer, |
| 133 uint32_t time, | 131 uint32_t time, |
| 134 wl_fixed_t x, | 132 wl_fixed_t x, |
| 135 wl_fixed_t y) { | 133 wl_fixed_t y) { |
| 136 MainLoopContext* context = static_cast<MainLoopContext*>(data); | 134 EventTimeStack* stack = static_cast<EventTimeStack*>(data); |
| 137 | 135 |
| 138 context->last_event_time = time; | 136 stack->push_back(time); |
| 139 } | 137 } |
| 140 | 138 |
| 141 void PointerButton(void* data, | 139 void PointerButton(void* data, |
| 142 wl_pointer* pointer, | 140 wl_pointer* pointer, |
| 143 uint32_t serial, | 141 uint32_t serial, |
| 144 uint32_t time, | 142 uint32_t time, |
| 145 uint32_t button, | 143 uint32_t button, |
| 146 uint32_t state) { | 144 uint32_t state) {} |
| 147 MainLoopContext* context = static_cast<MainLoopContext*>(data); | |
| 148 | |
| 149 context->shutdown = true; | |
| 150 } | |
| 151 | 145 |
| 152 void PointerAxis(void* data, | 146 void PointerAxis(void* data, |
| 153 wl_pointer* pointer, | 147 wl_pointer* pointer, |
| 154 uint32_t time, | 148 uint32_t time, |
| 155 uint32_t axis, | 149 uint32_t axis, |
| 156 wl_fixed_t value) {} | 150 wl_fixed_t value) {} |
| 157 | 151 |
| 158 void PointerAxisSource(void* data, wl_pointer* pointer, uint32_t axis_source) {} | 152 void PointerAxisSource(void* data, wl_pointer* pointer, uint32_t axis_source) {} |
| 159 | 153 |
| 160 void PointerAxisStop(void* data, | 154 void PointerAxisStop(void* data, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 183 uint32_t serial, | 177 uint32_t serial, |
| 184 uint32_t time, | 178 uint32_t time, |
| 185 int32_t id) {} | 179 int32_t id) {} |
| 186 | 180 |
| 187 void TouchMotion(void* data, | 181 void TouchMotion(void* data, |
| 188 wl_touch* touch, | 182 wl_touch* touch, |
| 189 uint32_t time, | 183 uint32_t time, |
| 190 int32_t id, | 184 int32_t id, |
| 191 wl_fixed_t x, | 185 wl_fixed_t x, |
| 192 wl_fixed_t y) { | 186 wl_fixed_t y) { |
| 193 MainLoopContext* context = static_cast<MainLoopContext*>(data); | 187 EventTimeStack* stack = static_cast<EventTimeStack*>(data); |
| 194 | 188 |
| 195 context->last_event_time = time; | 189 stack->push_back(time); |
| 196 } | 190 } |
| 197 | 191 |
| 198 void TouchFrame(void* data, wl_touch* touch) {} | 192 void TouchFrame(void* data, wl_touch* touch) {} |
| 199 | 193 |
| 200 void TouchCancel(void* data, wl_touch* touch) {} | 194 void TouchCancel(void* data, wl_touch* touch) {} |
| 201 | 195 |
| 196 struct Frame { |
| 197 uint32_t time = 0; |
| 198 bool callback_pending = false; |
| 199 }; |
| 200 |
| 202 void FrameCallback(void* data, wl_callback* callback, uint32_t time) { | 201 void FrameCallback(void* data, wl_callback* callback, uint32_t time) { |
| 203 MainLoopContext* context = static_cast<MainLoopContext*>(data); | 202 Frame* frame = static_cast<Frame*>(data); |
| 204 | 203 |
| 205 static uint32_t initial_time = time; | 204 static uint32_t initial_time = time; |
| 206 context->rotation = ((time - initial_time) / 1000.0) * kRotationSpeed; | 205 frame->time = time - initial_time; |
| 207 context->frame_callback_pending = false; | 206 frame->callback_pending = false; |
| 208 } | 207 } |
| 209 | 208 |
| 210 } // namespace | 209 } // namespace |
| 211 | 210 |
| 212 int MotionEventsMain() { | 211 class MotionEvents { |
| 212 public: |
| 213 MotionEvents() {} |
| 214 |
| 215 // Initialize and run client main loop. |
| 216 int Run(); |
| 217 |
| 218 private: |
| 219 DISALLOW_COPY_AND_ASSIGN(MotionEvents); |
| 220 }; |
| 221 |
| 222 int MotionEvents::Run() { |
| 213 std::unique_ptr<wl_display> display(wl_display_connect(nullptr)); | 223 std::unique_ptr<wl_display> display(wl_display_connect(nullptr)); |
| 214 if (!display) { | 224 if (!display) { |
| 215 LOG(ERROR) << "wl_display_connect failed"; | 225 LOG(ERROR) << "wl_display_connect failed"; |
| 216 return 1; | 226 return 1; |
| 217 } | 227 } |
| 218 | 228 |
| 219 wl_registry_listener registry_listener = {RegistryHandler, RegistryRemover}; | 229 wl_registry_listener registry_listener = {RegistryHandler, RegistryRemover}; |
| 220 | 230 |
| 221 Globals globals; | 231 Globals globals; |
| 222 wl_registry* registry = wl_display_get_registry(display.get()); | 232 wl_registry* registry = wl_display_get_registry(display.get()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 237 LOG(ERROR) << "Can't find shell interface"; | 247 LOG(ERROR) << "Can't find shell interface"; |
| 238 return 1; | 248 return 1; |
| 239 } | 249 } |
| 240 if (!globals.seat) { | 250 if (!globals.seat) { |
| 241 LOG(ERROR) << "Can't find seat interface"; | 251 LOG(ERROR) << "Can't find seat interface"; |
| 242 return 1; | 252 return 1; |
| 243 } | 253 } |
| 244 | 254 |
| 245 wl_buffer_listener buffer_listener = {BufferRelease}; | 255 wl_buffer_listener buffer_listener = {BufferRelease}; |
| 246 | 256 |
| 247 BufferState buffers[kBuffers]; | 257 Buffer buffers[kBuffers]; |
| 248 base::SharedMemory shared_memory; | 258 base::SharedMemory shared_memory; |
| 249 shared_memory.CreateAndMapAnonymous(kMemorySize); | 259 shared_memory.CreateAndMapAnonymous(kMemorySize); |
| 250 std::unique_ptr<wl_shm_pool> shm_pool( | 260 std::unique_ptr<wl_shm_pool> shm_pool( |
| 251 wl_shm_create_pool(globals.shm.get(), shared_memory.handle().fd, | 261 wl_shm_create_pool(globals.shm.get(), shared_memory.handle().fd, |
| 252 shared_memory.requested_size())); | 262 shared_memory.requested_size())); |
| 253 for (size_t i = 0; i < kBuffers; ++i) { | 263 for (size_t i = 0; i < kBuffers; ++i) { |
| 254 buffers[i].buffer.reset(static_cast<wl_buffer*>(wl_shm_pool_create_buffer( | 264 buffers[i].buffer.reset(static_cast<wl_buffer*>(wl_shm_pool_create_buffer( |
| 255 shm_pool.get(), i * kBufferSize, kWidth, kHeight, kStride, kFormat))); | 265 shm_pool.get(), i * kBufferSize, kWidth, kHeight, kStride, kFormat))); |
| 256 if (!buffers[i].buffer) { | 266 if (!buffers[i].buffer) { |
| 257 LOG(ERROR) << "Can't create buffer"; | 267 LOG(ERROR) << "Can't create buffer"; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 static_cast<wl_shell_surface*>( | 300 static_cast<wl_shell_surface*>( |
| 291 wl_shell_get_shell_surface(globals.shell.get(), surface.get()))); | 301 wl_shell_get_shell_surface(globals.shell.get(), surface.get()))); |
| 292 if (!shell_surface) { | 302 if (!shell_surface) { |
| 293 LOG(ERROR) << "Can't get shell surface"; | 303 LOG(ERROR) << "Can't get shell surface"; |
| 294 return 1; | 304 return 1; |
| 295 } | 305 } |
| 296 | 306 |
| 297 wl_shell_surface_set_title(shell_surface.get(), "Test Client"); | 307 wl_shell_surface_set_title(shell_surface.get(), "Test Client"); |
| 298 wl_shell_surface_set_toplevel(shell_surface.get()); | 308 wl_shell_surface_set_toplevel(shell_surface.get()); |
| 299 | 309 |
| 300 MainLoopContext context; | 310 EventTimeStack event_times; |
| 301 | 311 |
| 302 std::unique_ptr<wl_pointer> pointer( | 312 std::unique_ptr<wl_pointer> pointer( |
| 303 static_cast<wl_pointer*>(wl_seat_get_pointer(globals.seat.get()))); | 313 static_cast<wl_pointer*>(wl_seat_get_pointer(globals.seat.get()))); |
| 304 if (!pointer) { | 314 if (!pointer) { |
| 305 LOG(ERROR) << "Can't get pointer"; | 315 LOG(ERROR) << "Can't get pointer"; |
| 306 return 1; | 316 return 1; |
| 307 } | 317 } |
| 308 | 318 |
| 309 wl_pointer_listener pointer_listener = { | 319 wl_pointer_listener pointer_listener = { |
| 310 PointerEnter, PointerLeave, PointerMotion, | 320 PointerEnter, PointerLeave, PointerMotion, |
| 311 PointerButton, PointerAxis, PointerFrame, | 321 PointerButton, PointerAxis, PointerFrame, |
| 312 PointerAxisSource, PointerAxisStop, PointerDiscrete}; | 322 PointerAxisSource, PointerAxisStop, PointerDiscrete}; |
| 313 wl_pointer_add_listener(pointer.get(), &pointer_listener, &context); | 323 wl_pointer_add_listener(pointer.get(), &pointer_listener, &event_times); |
| 314 | 324 |
| 315 std::unique_ptr<wl_touch> touch( | 325 std::unique_ptr<wl_touch> touch( |
| 316 static_cast<wl_touch*>(wl_seat_get_touch(globals.seat.get()))); | 326 static_cast<wl_touch*>(wl_seat_get_touch(globals.seat.get()))); |
| 317 if (!touch) { | 327 if (!touch) { |
| 318 LOG(ERROR) << "Can't get touch"; | 328 LOG(ERROR) << "Can't get touch"; |
| 319 return 1; | 329 return 1; |
| 320 } | 330 } |
| 321 | 331 |
| 322 wl_touch_listener touch_listener = {TouchDown, TouchUp, TouchMotion, | 332 wl_touch_listener touch_listener = {TouchDown, TouchUp, TouchMotion, |
| 323 TouchFrame, TouchCancel}; | 333 TouchFrame, TouchCancel}; |
| 324 wl_touch_add_listener(touch.get(), &touch_listener, &context); | 334 wl_touch_add_listener(touch.get(), &touch_listener, &event_times); |
| 325 | 335 |
| 336 Frame frame; |
| 326 std::unique_ptr<wl_callback> frame_callback; | 337 std::unique_ptr<wl_callback> frame_callback; |
| 327 wl_callback_listener frame_listener = {FrameCallback}; | 338 wl_callback_listener frame_listener = {FrameCallback}; |
| 328 | 339 |
| 329 do { | 340 do { |
| 330 if (context.shutdown) | 341 if (frame.callback_pending) |
| 331 break; | |
| 332 | |
| 333 if (context.frame_callback_pending) | |
| 334 continue; | 342 continue; |
| 335 | 343 |
| 336 BufferState* buffer = | 344 Buffer* buffer = |
| 337 std::find_if(std::begin(buffers), std::end(buffers), | 345 std::find_if(std::begin(buffers), std::end(buffers), |
| 338 [](const BufferState& buffer) { return !buffer.busy; }); | 346 [](const Buffer& buffer) { return !buffer.busy; }); |
| 339 if (buffer == std::end(buffers)) | 347 if (buffer == std::end(buffers)) |
| 340 continue; | 348 continue; |
| 341 | 349 |
| 342 SkCanvas* canvas = buffer->sk_surface->getCanvas(); | 350 SkCanvas* canvas = buffer->sk_surface->getCanvas(); |
| 343 canvas->save(); | 351 canvas->save(); |
| 344 canvas->clear(SkColorSetRGB((context.last_event_time & 0x0000ff) >> 0, | 352 |
| 345 (context.last_event_time & 0x00ff00) >> 8, | 353 // Clear background to black. |
| 346 (context.last_event_time & 0xff0000) >> 16)); | 354 canvas->clear(SK_ColorBLACK); |
| 355 |
| 356 // Split buffer into one horizontal rectangle for each event received since |
| 357 // last frame. Latest event at the top. |
| 358 if (!event_times.empty()) { |
| 359 double y = 0; |
| 360 double height = static_cast<double>(kHeight) / event_times.size(); |
| 361 while (!event_times.empty()) { |
| 362 SkRect rect = SkRect::MakeXYWH(0, y, kWidth, height); |
| 363 SkPaint paint; |
| 364 paint.setColor(SkColorSetRGB((event_times.back() & 0x0000ff) >> 0, |
| 365 (event_times.back() & 0x00ff00) >> 8, |
| 366 (event_times.back() & 0xff0000) >> 16)); |
| 367 canvas->drawRect(rect, paint); |
| 368 event_times.pop_back(); |
| 369 y += height; |
| 370 } |
| 371 } |
| 372 |
| 373 // Draw a blue rotating rectangle on top. |
| 347 canvas->translate(SkIntToScalar(kWidth / 2), SkIntToScalar(kHeight / 2)); | 374 canvas->translate(SkIntToScalar(kWidth / 2), SkIntToScalar(kHeight / 2)); |
| 348 canvas->rotate(SkDoubleToScalar(context.rotation)); | 375 canvas->rotate(SkDoubleToScalar((frame.time / 1000.0f) * kRotationSpeed)); |
| 349 SkRect rect = SkRect::MakeXYWH(-(kWidth / 4.0f), -(kHeight / 4.0f), | 376 SkRect rect = SkRect::MakeXYWH(-(kWidth / 4.0f), -(kHeight / 4.0f), |
| 350 kWidth / 2.0f, kHeight / 2.0f); | 377 kWidth / 2.0f, kHeight / 2.0f); |
| 351 SkPaint paint; | 378 SkPaint paint; |
| 352 paint.setColor(SK_ColorBLUE); | 379 paint.setColor(SK_ColorBLUE); |
| 353 canvas->drawRect(rect, paint); | 380 canvas->drawRect(rect, paint); |
| 381 |
| 354 canvas->restore(); | 382 canvas->restore(); |
| 355 | 383 |
| 356 wl_surface_attach(surface.get(), buffer->buffer.get(), 0, 0); | 384 wl_surface_attach(surface.get(), buffer->buffer.get(), 0, 0); |
| 357 buffer->busy = true; | 385 buffer->busy = true; |
| 358 | 386 |
| 359 frame_callback.reset(wl_surface_frame(surface.get())); | 387 frame_callback.reset(wl_surface_frame(surface.get())); |
| 360 wl_callback_add_listener(frame_callback.get(), &frame_listener, &context); | 388 wl_callback_add_listener(frame_callback.get(), &frame_listener, &frame); |
| 361 context.frame_callback_pending = true; | 389 frame.callback_pending = true; |
| 362 | 390 |
| 363 wl_surface_commit(surface.get()); | 391 wl_surface_commit(surface.get()); |
| 364 wl_display_flush(display.get()); | 392 wl_display_flush(display.get()); |
| 365 } while (wl_display_dispatch(display.get()) != -1); | 393 } while (wl_display_dispatch(display.get()) != -1); |
| 366 | 394 |
| 367 return 0; | 395 return 0; |
| 368 } | 396 } |
| 369 | 397 |
| 370 } // namespace clients | 398 } // namespace clients |
| 371 } // namespace wayland | 399 } // namespace wayland |
| 372 } // namespace exo | 400 } // namespace exo |
| 373 | 401 |
| 374 int main() { | 402 int main() { |
| 375 return exo::wayland::clients::MotionEventsMain(); | 403 return exo::wayland::clients::MotionEvents().Run(); |
| 376 } | 404 } |
| OLD | NEW |