Zakero's C++ Header Libraries
A collection of reusable C++ libraries
Zakero_Yetani.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2020 Andrew Moore
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7  */
8 
9 #ifndef zakero_Yetani_h
10 #define zakero_Yetani_h
11 
222 /******************************************************************************
223  * Includes
224  */
225 
226 #include <iostream>
227 #include <thread>
228 
229 // POSIX
230 #include <poll.h>
231 
232 // Linux
233 #include <linux/input-event-codes.h>
234 
235 // Wayland
236 #include <wayland/wayland-client.h>
237 
238 // Zakero
239 #include "Zakero_Base.h"
240 #include "Zakero_MemoryPool.h"
241 
242 
243 /******************************************************************************
244  * Macros
245  */
246 
247 // {{{ Macros
248 
265 #define ZAKERO_YETANI__ERROR_DATA \
266  X(Error_None , 0 , "No Error" ) \
267  X(Error_Compositor_Was_Not_Found , 1 , "Could not find the Compositor object in the Global Repository." ) \
268  X(Error_Connection_Failed , 2 , "Failed to connect to the Wayland Server." ) \
269  X(Error_Cursor_Already_Exists , 3 , "A cursor with that name already exists." ) \
270  X(Error_Cursor_Does_Not_Exist , 4 , "No cursors exists with that name." ) \
271  X(Error_Cursor_Frame_Time_Too_Large , 5 , "The cursor time per frame is too large, must be <= Size_Max." ) \
272  X(Error_Cursor_Frame_Time_Too_Small , 6 , "The cursor time per frame is too small, must be greater than 0." ) \
273  X(Error_Cursor_Image_Data_Is_Empty , 7 , "The cursor image data can not be empty." ) \
274  X(Error_Cursor_Name_Is_Invalid , 8 , "The cursor name is invalid." ) \
275  X(Error_Cursor_Not_Attached , 9 , "The specified cursor is not attached/in-use." ) \
276  X(Error_Cursor_Size_Too_Small , 10 , "The cursor size, both width and height must be greater than 0." ) \
277  X(Error_Invalid_Display_Name , 11 , "An invalid dispaly name was given to the Wayland Server." ) \
278  X(Error_Minimum_Size_Greater_Than_Maximum_Size , 12 , "The minimum window size is larger than the maximum window size." ) \
279  X(Error_No_Output_Available , 13 , "No output devices are available." ) \
280  X(Error_Registry_Not_Available , 14 , "Unable to get the registery." ) \
281  X(Error_Server_Side_Decorations_Not_Available , 15 , "The Wayland Compositor does not support Server Side Decorations." ) \
282  X(Error_Shm_Was_Not_Found , 16 , "Could not find the Shm object in the Global Repository." ) \
283  X(Error_Wayland_Not_Available , 17 , "Could not find the Wayland Server." ) \
284  X(Error_Window_Initialization_Failed , 18 , "The window was not able to be initialized." ) \
285  X(Error_Window_Size_Too_Small , 19 , "The window size was too small." ) \
286  X(Error_Xdg_WM_Base_Was_Not_Found , 20 , "Could not find the XDG WM Base object the Global Repository." ) \
287 
288  /* --- To Be Deleted --- */
289  /*
290  X(Error_Window_Already_Exists , 100 , "A window with that name already exists." ) \
291  X(Error_Window_Does_Not_Exist , 101 , "No windows exists with that name." ) \
292  X(Error_Window_Name_Can_Not_Be_Empty , 102 , "Windows can not have empty names." ) \
293  X(Error_EventLoop_Is_Already_Running , 103 , "Can't start the event loop since it is already running." ) \
294  X(Error_Connection_Not_Initialized , 104 , "Not connected to the Wayland Server." ) \
295  X(Error_Connection_Already_Established , 105 , "Must disconnect before establishing a new connection." ) \
296  X(Error_Seat_Was_Not_Found , 106 , "Could not find the Seat object in the Global Repository." ) \
297  X(Error_Present_Current_Image_First , 107 , "The next image has already been retrieved and must be presented." ) \
298  X(Error_No_Image_Is_Available , 108 , "No image is available to be retrieved." ) \
299  X(Error_Window_Is_Locked , 109 , "The window access is restricted due to being locked." ) \
300  X(Error_Cursor_Image_Data_Size_Is_Invalid , 110 , "The cursor image data size does not match the configuration." ) \
301  */
302 
303 // }}}
304 
305 /******************************************************************************
306  * Generated Code
307  *
308  * The code is this section was created by "wayland-protocol/protocol.sh". The
309  * generated code is required since the XDG/Wayland headers are not officially
310  * distributed. Plus, there are many versions of the generated code with
311  * slight variations. By including the code directly, the generated code is
312  * from a known baseline.
313  *
314  * TL;DR: The code you are looking for is in the Yetani class.
315  */
316 
321 /*
322  * The "wayland-protocol/protocol.sh" script uses this fold as markers to know
323  * where to add and remove code.
324  */
325 // {{{ Generated Code
326 // {{{ xdg-decoration-unstable-v1
327 struct xdg_toplevel;
328 struct zxdg_decoration_manager_v1;
329 struct zxdg_toplevel_decoration_v1;
330 extern const struct wl_interface zxdg_decoration_manager_v1_interface;
331 extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
332 static inline void
333 zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data)
334 {
335  wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data);
336 }
337 static inline void *
338 zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
339 {
340  return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1);
341 }
342 static inline uint32_t
343 zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
344 {
345  return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1);
346 }
347 static inline void
348 zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
349 {
350  wl_proxy_marshal((struct wl_proxy *) zxdg_decoration_manager_v1,
351  0);
352  wl_proxy_destroy((struct wl_proxy *) zxdg_decoration_manager_v1);
353 }
354 static inline struct zxdg_toplevel_decoration_v1 *
355 zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel)
356 {
357  struct wl_proxy *id;
358  id = wl_proxy_marshal_constructor((struct wl_proxy *) zxdg_decoration_manager_v1,
359  1, &zxdg_toplevel_decoration_v1_interface, NULL, toplevel);
360  return (struct zxdg_toplevel_decoration_v1 *) id;
361 }
362 enum zxdg_toplevel_decoration_v1_error {
363  ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0,
364  ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1,
365  ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2,
366 };
367 enum zxdg_toplevel_decoration_v1_mode {
368  ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1,
369  ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2,
370 };
371 struct zxdg_toplevel_decoration_v1_listener {
372  void (*configure)(void *data,
373  struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
374  uint32_t mode);
375 };
376 static inline int
377 zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
378  const struct zxdg_toplevel_decoration_v1_listener *listener, void *data)
379 {
380  return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1,
381  (void (**)(void)) listener, data);
382 }
383 static inline void
384 zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data)
385 {
386  wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data);
387 }
388 static inline void *
389 zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
390 {
391  return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1);
392 }
393 static inline uint32_t
394 zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
395 {
396  return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1);
397 }
398 static inline void
399 zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
400 {
401  wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
402  0);
403  wl_proxy_destroy((struct wl_proxy *) zxdg_toplevel_decoration_v1);
404 }
405 static inline void
406 zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode)
407 {
408  wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
409  1, mode);
410 }
411 static inline void
412 zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
413 {
414  wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
415  2);
416 }
417 #ifdef ZAKERO_YETANI_IMPLEMENTATION
418 extern const struct wl_interface xdg_toplevel_interface;
419 extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
420 static const struct wl_interface *xdg_decoration_unstable_v1_types[] = {
421  NULL,
422  &zxdg_toplevel_decoration_v1_interface,
423  &xdg_toplevel_interface,
424 };
425 static const struct wl_message zxdg_decoration_manager_v1_requests[] = {
426  { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
427  { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 },
428 };
429 const struct wl_interface zxdg_decoration_manager_v1_interface = {
430  "zxdg_decoration_manager_v1", 1,
431  2, zxdg_decoration_manager_v1_requests,
432  0, NULL,
433 };
434 static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = {
435  { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
436  { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 },
437  { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 },
438 };
439 static const struct wl_message zxdg_toplevel_decoration_v1_events[] = {
440  { "configure", "u", xdg_decoration_unstable_v1_types + 0 },
441 };
442 const struct wl_interface zxdg_toplevel_decoration_v1_interface = {
443  "zxdg_toplevel_decoration_v1", 1,
444  3, zxdg_toplevel_decoration_v1_requests,
445  1, zxdg_toplevel_decoration_v1_events,
446 };
447 #endif // ZAKERO_YETANI_IMPLEMENTATION
448 // }}}
449 // {{{ xdg-shell
450 struct wl_output;
451 struct wl_seat;
452 struct wl_surface;
453 struct xdg_popup;
454 struct xdg_positioner;
455 struct xdg_surface;
456 struct xdg_toplevel;
457 struct xdg_wm_base;
458 extern const struct wl_interface xdg_wm_base_interface;
459 extern const struct wl_interface xdg_positioner_interface;
460 extern const struct wl_interface xdg_surface_interface;
461 extern const struct wl_interface xdg_toplevel_interface;
462 extern const struct wl_interface xdg_popup_interface;
463 enum xdg_wm_base_error {
464  XDG_WM_BASE_ERROR_ROLE = 0,
465  XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1,
466  XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2,
467  XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3,
468  XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4,
469  XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5,
470 };
471 struct xdg_wm_base_listener {
472  void (*ping)(void *data,
473  struct xdg_wm_base *xdg_wm_base,
474  uint32_t serial);
475 };
476 static inline int
477 xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base,
478  const struct xdg_wm_base_listener *listener, void *data)
479 {
480  return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base,
481  (void (**)(void)) listener, data);
482 }
483 static inline void
484 xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data)
485 {
486  wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data);
487 }
488 static inline void *
489 xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base)
490 {
491  return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base);
492 }
493 static inline uint32_t
494 xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base)
495 {
496  return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base);
497 }
498 static inline void
499 xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base)
500 {
501  wl_proxy_marshal((struct wl_proxy *) xdg_wm_base,
502  0);
503  wl_proxy_destroy((struct wl_proxy *) xdg_wm_base);
504 }
505 static inline struct xdg_positioner *
506 xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base)
507 {
508  struct wl_proxy *id;
509  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base,
510  1, &xdg_positioner_interface, NULL);
511  return (struct xdg_positioner *) id;
512 }
513 static inline struct xdg_surface *
514 xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface)
515 {
516  struct wl_proxy *id;
517  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base,
518  2, &xdg_surface_interface, NULL, surface);
519  return (struct xdg_surface *) id;
520 }
521 static inline void
522 xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial)
523 {
524  wl_proxy_marshal((struct wl_proxy *) xdg_wm_base,
525  3, serial);
526 }
527 enum xdg_positioner_error {
528  XDG_POSITIONER_ERROR_INVALID_INPUT = 0,
529 };
530 enum xdg_positioner_anchor {
531  XDG_POSITIONER_ANCHOR_NONE = 0,
532  XDG_POSITIONER_ANCHOR_TOP = 1,
533  XDG_POSITIONER_ANCHOR_BOTTOM = 2,
534  XDG_POSITIONER_ANCHOR_LEFT = 3,
535  XDG_POSITIONER_ANCHOR_RIGHT = 4,
536  XDG_POSITIONER_ANCHOR_TOP_LEFT = 5,
537  XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6,
538  XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7,
539  XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8,
540 };
541 enum xdg_positioner_gravity {
542  XDG_POSITIONER_GRAVITY_NONE = 0,
543  XDG_POSITIONER_GRAVITY_TOP = 1,
544  XDG_POSITIONER_GRAVITY_BOTTOM = 2,
545  XDG_POSITIONER_GRAVITY_LEFT = 3,
546  XDG_POSITIONER_GRAVITY_RIGHT = 4,
547  XDG_POSITIONER_GRAVITY_TOP_LEFT = 5,
548  XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6,
549  XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7,
550  XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8,
551 };
552 enum xdg_positioner_constraint_adjustment {
553  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0,
554  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1,
555  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2,
556  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4,
557  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8,
558  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16,
559  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32,
560 };
561 static inline void
562 xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data)
563 {
564  wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data);
565 }
566 static inline void *
567 xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner)
568 {
569  return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner);
570 }
571 static inline uint32_t
572 xdg_positioner_get_version(struct xdg_positioner *xdg_positioner)
573 {
574  return wl_proxy_get_version((struct wl_proxy *) xdg_positioner);
575 }
576 static inline void
577 xdg_positioner_destroy(struct xdg_positioner *xdg_positioner)
578 {
579  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
580  0);
581  wl_proxy_destroy((struct wl_proxy *) xdg_positioner);
582 }
583 static inline void
584 xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height)
585 {
586  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
587  1, width, height);
588 }
589 static inline void
590 xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height)
591 {
592  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
593  2, x, y, width, height);
594 }
595 static inline void
596 xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor)
597 {
598  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
599  3, anchor);
600 }
601 static inline void
602 xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity)
603 {
604  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
605  4, gravity);
606 }
607 static inline void
608 xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment)
609 {
610  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
611  5, constraint_adjustment);
612 }
613 static inline void
614 xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y)
615 {
616  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
617  6, x, y);
618 }
619 static inline void
620 xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner)
621 {
622  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
623  7);
624 }
625 static inline void
626 xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height)
627 {
628  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
629  8, parent_width, parent_height);
630 }
631 static inline void
632 xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial)
633 {
634  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
635  9, serial);
636 }
637 enum xdg_surface_error {
638  XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1,
639  XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2,
640  XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3,
641 };
642 struct xdg_surface_listener {
643  void (*configure)(void *data,
644  struct xdg_surface *xdg_surface,
645  uint32_t serial);
646 };
647 static inline int
648 xdg_surface_add_listener(struct xdg_surface *xdg_surface,
649  const struct xdg_surface_listener *listener, void *data)
650 {
651  return wl_proxy_add_listener((struct wl_proxy *) xdg_surface,
652  (void (**)(void)) listener, data);
653 }
654 static inline void
655 xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)
656 {
657  wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data);
658 }
659 static inline void *
660 xdg_surface_get_user_data(struct xdg_surface *xdg_surface)
661 {
662  return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface);
663 }
664 static inline uint32_t
665 xdg_surface_get_version(struct xdg_surface *xdg_surface)
666 {
667  return wl_proxy_get_version((struct wl_proxy *) xdg_surface);
668 }
669 static inline void
670 xdg_surface_destroy(struct xdg_surface *xdg_surface)
671 {
672  wl_proxy_marshal((struct wl_proxy *) xdg_surface,
673  0);
674  wl_proxy_destroy((struct wl_proxy *) xdg_surface);
675 }
676 static inline struct xdg_toplevel *
677 xdg_surface_get_toplevel(struct xdg_surface *xdg_surface)
678 {
679  struct wl_proxy *id;
680  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface,
681  1, &xdg_toplevel_interface, NULL);
682  return (struct xdg_toplevel *) id;
683 }
684 static inline struct xdg_popup *
685 xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner)
686 {
687  struct wl_proxy *id;
688  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface,
689  2, &xdg_popup_interface, NULL, parent, positioner);
690  return (struct xdg_popup *) id;
691 }
692 static inline void
693 xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height)
694 {
695  wl_proxy_marshal((struct wl_proxy *) xdg_surface,
696  3, x, y, width, height);
697 }
698 static inline void
699 xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)
700 {
701  wl_proxy_marshal((struct wl_proxy *) xdg_surface,
702  4, serial);
703 }
704 enum xdg_toplevel_resize_edge {
705  XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0,
706  XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1,
707  XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2,
708  XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4,
709  XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5,
710  XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6,
711  XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8,
712  XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9,
713  XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10,
714 };
715 enum xdg_toplevel_state {
716  XDG_TOPLEVEL_STATE_MAXIMIZED = 1,
717  XDG_TOPLEVEL_STATE_FULLSCREEN = 2,
718  XDG_TOPLEVEL_STATE_RESIZING = 3,
719  XDG_TOPLEVEL_STATE_ACTIVATED = 4,
720  XDG_TOPLEVEL_STATE_TILED_LEFT = 5,
721  XDG_TOPLEVEL_STATE_TILED_RIGHT = 6,
722  XDG_TOPLEVEL_STATE_TILED_TOP = 7,
723  XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8,
724 };
725 struct xdg_toplevel_listener {
726  void (*configure)(void *data,
727  struct xdg_toplevel *xdg_toplevel,
728  int32_t width,
729  int32_t height,
730  struct wl_array *states);
731  void (*close)(void *data,
732  struct xdg_toplevel *xdg_toplevel);
733 };
734 static inline int
735 xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel,
736  const struct xdg_toplevel_listener *listener, void *data)
737 {
738  return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel,
739  (void (**)(void)) listener, data);
740 }
741 static inline void
742 xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data)
743 {
744  wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data);
745 }
746 static inline void *
747 xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel)
748 {
749  return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel);
750 }
751 static inline uint32_t
752 xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel)
753 {
754  return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel);
755 }
756 static inline void
757 xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel)
758 {
759  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
760  0);
761  wl_proxy_destroy((struct wl_proxy *) xdg_toplevel);
762 }
763 static inline void
764 xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent)
765 {
766  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
767  1, parent);
768 }
769 static inline void
770 xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title)
771 {
772  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
773  2, title);
774 }
775 static inline void
776 xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id)
777 {
778  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
779  3, app_id);
780 }
781 static inline void
782 xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
783 {
784  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
785  4, seat, serial, x, y);
786 }
787 static inline void
788 xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial)
789 {
790  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
791  5, seat, serial);
792 }
793 static inline void
794 xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges)
795 {
796  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
797  6, seat, serial, edges);
798 }
799 static inline void
800 xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
801 {
802  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
803  7, width, height);
804 }
805 static inline void
806 xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
807 {
808  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
809  8, width, height);
810 }
811 static inline void
812 xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel)
813 {
814  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
815  9);
816 }
817 static inline void
818 xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel)
819 {
820  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
821  10);
822 }
823 static inline void
824 xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output)
825 {
826  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
827  11, output);
828 }
829 static inline void
830 xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel)
831 {
832  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
833  12);
834 }
835 static inline void
836 xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel)
837 {
838  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
839  13);
840 }
841 enum xdg_popup_error {
842  XDG_POPUP_ERROR_INVALID_GRAB = 0,
843 };
844 struct xdg_popup_listener {
845  void (*configure)(void *data,
846  struct xdg_popup *xdg_popup,
847  int32_t x,
848  int32_t y,
849  int32_t width,
850  int32_t height);
851  void (*popup_done)(void *data,
852  struct xdg_popup *xdg_popup);
853  void (*repositioned)(void *data,
854  struct xdg_popup *xdg_popup,
855  uint32_t token);
856 };
857 static inline int
858 xdg_popup_add_listener(struct xdg_popup *xdg_popup,
859  const struct xdg_popup_listener *listener, void *data)
860 {
861  return wl_proxy_add_listener((struct wl_proxy *) xdg_popup,
862  (void (**)(void)) listener, data);
863 }
864 static inline void
865 xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data)
866 {
867  wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data);
868 }
869 static inline void *
870 xdg_popup_get_user_data(struct xdg_popup *xdg_popup)
871 {
872  return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup);
873 }
874 static inline uint32_t
875 xdg_popup_get_version(struct xdg_popup *xdg_popup)
876 {
877  return wl_proxy_get_version((struct wl_proxy *) xdg_popup);
878 }
879 static inline void
880 xdg_popup_destroy(struct xdg_popup *xdg_popup)
881 {
882  wl_proxy_marshal((struct wl_proxy *) xdg_popup,
883  0);
884  wl_proxy_destroy((struct wl_proxy *) xdg_popup);
885 }
886 static inline void
887 xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial)
888 {
889  wl_proxy_marshal((struct wl_proxy *) xdg_popup,
890  1, seat, serial);
891 }
892 static inline void
893 xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token)
894 {
895  wl_proxy_marshal((struct wl_proxy *) xdg_popup,
896  2, positioner, token);
897 }
898 #ifdef ZAKERO_YETANI_IMPLEMENTATION
899 extern const struct wl_interface wl_output_interface;
900 extern const struct wl_interface wl_seat_interface;
901 extern const struct wl_interface wl_surface_interface;
902 extern const struct wl_interface xdg_popup_interface;
903 extern const struct wl_interface xdg_positioner_interface;
904 extern const struct wl_interface xdg_surface_interface;
905 extern const struct wl_interface xdg_toplevel_interface;
906 static const struct wl_interface *xdg_shell_types[] = {
907  NULL,
908  NULL,
909  NULL,
910  NULL,
911  &xdg_positioner_interface,
912  &xdg_surface_interface,
913  &wl_surface_interface,
914  &xdg_toplevel_interface,
915  &xdg_popup_interface,
916  &xdg_surface_interface,
917  &xdg_positioner_interface,
918  &xdg_toplevel_interface,
919  &wl_seat_interface,
920  NULL,
921  NULL,
922  NULL,
923  &wl_seat_interface,
924  NULL,
925  &wl_seat_interface,
926  NULL,
927  NULL,
928  &wl_output_interface,
929  &wl_seat_interface,
930  NULL,
931  &xdg_positioner_interface,
932  NULL,
933 };
934 static const struct wl_message xdg_wm_base_requests[] = {
935  { "destroy", "", xdg_shell_types + 0 },
936  { "create_positioner", "n", xdg_shell_types + 4 },
937  { "get_xdg_surface", "no", xdg_shell_types + 5 },
938  { "pong", "u", xdg_shell_types + 0 },
939 };
940 static const struct wl_message xdg_wm_base_events[] = {
941  { "ping", "u", xdg_shell_types + 0 },
942 };
943 const struct wl_interface xdg_wm_base_interface = {
944  "xdg_wm_base", 3,
945  4, xdg_wm_base_requests,
946  1, xdg_wm_base_events,
947 };
948 static const struct wl_message xdg_positioner_requests[] = {
949  { "destroy", "", xdg_shell_types + 0 },
950  { "set_size", "ii", xdg_shell_types + 0 },
951  { "set_anchor_rect", "iiii", xdg_shell_types + 0 },
952  { "set_anchor", "u", xdg_shell_types + 0 },
953  { "set_gravity", "u", xdg_shell_types + 0 },
954  { "set_constraint_adjustment", "u", xdg_shell_types + 0 },
955  { "set_offset", "ii", xdg_shell_types + 0 },
956  { "set_reactive", "3", xdg_shell_types + 0 },
957  { "set_parent_size", "3ii", xdg_shell_types + 0 },
958  { "set_parent_configure", "3u", xdg_shell_types + 0 },
959 };
960 const struct wl_interface xdg_positioner_interface = {
961  "xdg_positioner", 3,
962  10, xdg_positioner_requests,
963  0, NULL,
964 };
965 static const struct wl_message xdg_surface_requests[] = {
966  { "destroy", "", xdg_shell_types + 0 },
967  { "get_toplevel", "n", xdg_shell_types + 7 },
968  { "get_popup", "n?oo", xdg_shell_types + 8 },
969  { "set_window_geometry", "iiii", xdg_shell_types + 0 },
970  { "ack_configure", "u", xdg_shell_types + 0 },
971 };
972 static const struct wl_message xdg_surface_events[] = {
973  { "configure", "u", xdg_shell_types + 0 },
974 };
975 const struct wl_interface xdg_surface_interface = {
976  "xdg_surface", 3,
977  5, xdg_surface_requests,
978  1, xdg_surface_events,
979 };
980 static const struct wl_message xdg_toplevel_requests[] = {
981  { "destroy", "", xdg_shell_types + 0 },
982  { "set_parent", "?o", xdg_shell_types + 11 },
983  { "set_title", "s", xdg_shell_types + 0 },
984  { "set_app_id", "s", xdg_shell_types + 0 },
985  { "show_window_menu", "ouii", xdg_shell_types + 12 },
986  { "move", "ou", xdg_shell_types + 16 },
987  { "resize", "ouu", xdg_shell_types + 18 },
988  { "set_max_size", "ii", xdg_shell_types + 0 },
989  { "set_min_size", "ii", xdg_shell_types + 0 },
990  { "set_maximized", "", xdg_shell_types + 0 },
991  { "unset_maximized", "", xdg_shell_types + 0 },
992  { "set_fullscreen", "?o", xdg_shell_types + 21 },
993  { "unset_fullscreen", "", xdg_shell_types + 0 },
994  { "set_minimized", "", xdg_shell_types + 0 },
995 };
996 static const struct wl_message xdg_toplevel_events[] = {
997  { "configure", "iia", xdg_shell_types + 0 },
998  { "close", "", xdg_shell_types + 0 },
999 };
1000 const struct wl_interface xdg_toplevel_interface = {
1001  "xdg_toplevel", 3,
1002  14, xdg_toplevel_requests,
1003  2, xdg_toplevel_events,
1004 };
1005 static const struct wl_message xdg_popup_requests[] = {
1006  { "destroy", "", xdg_shell_types + 0 },
1007  { "grab", "ou", xdg_shell_types + 22 },
1008  { "reposition", "3ou", xdg_shell_types + 24 },
1009 };
1010 static const struct wl_message xdg_popup_events[] = {
1011  { "configure", "iiii", xdg_shell_types + 0 },
1012  { "popup_done", "", xdg_shell_types + 0 },
1013  { "repositioned", "3u", xdg_shell_types + 0 },
1014 };
1015 const struct wl_interface xdg_popup_interface = {
1016  "xdg_popup", 3,
1017  3, xdg_popup_requests,
1018  3, xdg_popup_events,
1019 };
1020 #endif // ZAKERO_YETANI_IMPLEMENTATION
1021 // }}}
1022 // }}}
1023 
1028 namespace zakero
1029 {
1030  // {{{ Declaration
1031 
1032  class Yetani
1033  {
1034  public:
1035 #define X(name_, val_, mesg_) \
1036  static constexpr int name_ = val_;
1037  ZAKERO_YETANI__ERROR_DATA
1038 #undef X
1039 
1040  virtual ~Yetani() noexcept;
1041 
1042  // {{{ Type : Key
1043 
1044  enum struct KeyState
1045  { Released = 0
1046  , Pressed = 1
1047  , Repeat = 2
1048  };
1049 
1050  struct Key
1051  {
1052  uint32_t time;
1053  uint32_t code;
1055  };
1056 
1057  static constexpr uint32_t KeyModifier_Shift = 0x00000001;
1058  static constexpr uint32_t KeyModifier_CapsLock = 0x00000002;
1059  static constexpr uint32_t KeyModifier_Control = 0x00000004;
1060  static constexpr uint32_t KeyModifier_Alt = 0x00000008;
1061  static constexpr uint32_t KeyModifier_NumLock = 0x00000010;
1062  static constexpr uint32_t KeyModifier_Meta = 0x00000040;
1063 
1065  {
1066  uint32_t pressed = 0;
1067  uint32_t latched = 0;
1068  uint32_t locked = 0;
1069  uint32_t group = 0;
1070  };
1071 
1072  // }}}
1073  // {{{ Type : Point
1074 
1075  struct PointMm
1076  {
1077  uint32_t time;
1078  float x;
1079  float y;
1080 
1081  friend bool operator==(Yetani::PointMm&, Yetani::PointMm&) noexcept;
1082  };
1083 
1085  {
1086  uint32_t time;
1087  float x;
1088  float y;
1089 
1090  friend bool operator==(Yetani::PointPercent&, Yetani::PointPercent&) noexcept;
1091  };
1092 
1093  struct PointPixel
1094  {
1095  uint32_t time;
1096  int32_t x;
1097  int32_t y;
1098 
1099  friend bool operator==(Yetani::PointPixel&, Yetani::PointPixel&) noexcept;
1100  };
1101 
1102  // }}}
1103  // {{{ Type : Pointer Axis
1104 
1105  enum struct PointerAxisSource
1106  { Unknown
1107  , Continuous
1108  , Finger
1109  , Wheel
1110  , Wheel_Tilt
1111  };
1112 
1113  enum struct PointerAxisType
1114  { Unknown
1115  , Horizontal
1116  , Vertical
1117  };
1118 
1120  {
1121  uint32_t time;
1122  int32_t steps;
1123  float distance;
1126  };
1127 
1128  // }}}
1129  // {{{ Type : Pointer Button
1130 
1132  { Released = 0
1133  , Pressed = 1
1134  };
1135 
1137  {
1138  uint32_t code;
1140  };
1141 
1142  // }}}
1143  // {{{ Type : Size
1144 
1145  struct SizeMm
1146  {
1147  float width;
1148  float height;
1149 
1150  friend bool operator==(Yetani::SizeMm&, Yetani::SizeMm&) noexcept;
1151  };
1152 
1154  {
1155  float width;
1156  float height;
1157 
1158  friend bool operator==(Yetani::SizePercent&, Yetani::SizePercent&) noexcept;
1159  };
1160 
1161  struct SizePixel
1162  {
1163  int32_t width;
1164  int32_t height;
1165 
1166  friend bool operator==(Yetani::SizePixel&, Yetani::SizePixel&) noexcept;
1167  };
1168 
1169  // }}}
1170  // {{{ Connection
1171 
1172  static Yetani* connect() noexcept;
1173  static Yetani* connect(const std::string&) noexcept;
1174  static Yetani* connect(std::error_code&) noexcept;
1175  static Yetani* connect(const std::string&, std::error_code&) noexcept;
1176 
1177  // }}}
1178  // {{{ Cursor
1179 
1181  {
1183  wl_shm_format format = WL_SHM_FORMAT_ARGB8888;
1184  int32_t hotspot_x = 0;
1185  int32_t hotspot_y = 0;
1186  std::chrono::milliseconds time_per_frame = std::chrono::milliseconds(0);
1187  const std::vector<void*>& image_data;
1188  };
1189 
1190  // -------------------------------------------------- //
1191 
1192  std::error_code cursorCreate(const std::string&, const Yetani::CursorConfig&) noexcept;
1193  std::error_code cursorDestroy(const std::string&) noexcept;
1194 
1195  // }}}
1196  // {{{ Keyboard
1197 
1198  int32_t keyRepeatDelay() const noexcept;
1199  int32_t keyRepeatRate() const noexcept;
1200 
1201  // }}}
1202  // {{{ Output : Wayland
1203 
1204  struct Output
1205  {
1206  std::string make = "";
1207  std::string model = "";
1208  int32_t x = 0;
1209  int32_t y = 0;
1210  int32_t width = 0;
1211  int32_t height = 0;
1212  uint32_t physical_width_mm = 0;
1213  uint32_t physical_height_mm = 0;
1214  int32_t subpixel = 0;
1215  int32_t refresh_mHz = 0;
1216  int32_t scale_factor = 0;
1217  int32_t transform = 0;
1218  uint32_t flags = 0;
1219  float pixels_per_mm_horizontal = 0.0;
1220  float pixels_per_mm_vertical = 0.0;
1221  };
1222 
1223  // -------------------------------------------------- //
1224 
1225  using OutputId = uint32_t;
1226 
1227  using LambdaOutputId = std::function<void(const Yetani::OutputId)>;
1228 
1229  using VectorOutputId = std::vector<OutputId>;
1230 
1231  // -------------------------------------------------- //
1232 
1233  Yetani::Output output(const Yetani::OutputId) const noexcept;
1234  Yetani::VectorOutputId outputVector() const noexcept;
1235  static std::string outputSubpixelName(int32_t) noexcept;
1236  static std::string outputTransformName(int32_t) noexcept;
1237 
1238  Yetani::PointMm outputConvertToMm(const Yetani::OutputId, const Yetani::PointPixel&) const noexcept;
1239  Yetani::PointPercent outputConvertToPercent(const Yetani::OutputId, const Yetani::PointPixel&) const noexcept;
1240  Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointMm&) const noexcept;
1241  Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointPercent&) const noexcept;
1242 
1243  Yetani::SizeMm outputConvertToMm(const Yetani::OutputId, const Yetani::SizePixel&) const noexcept;
1244  Yetani::SizePercent outputConvertToPercent(const Yetani::OutputId, const Yetani::SizePixel&) const noexcept;
1245  Yetani::SizePixel outputConvertToPixel(const Yetani::OutputId, const Yetani::SizeMm&) const noexcept;
1246  Yetani::SizePixel outputConvertToPixel(const Yetani::OutputId, const Yetani::SizePercent&) const noexcept;
1247 
1248  void outputOnAdd(Yetani::LambdaOutputId) noexcept;
1249  void outputOnChange(Yetani::LambdaOutputId) noexcept;
1250  void outputOnRemove(Yetani::LambdaOutputId) noexcept;
1251 
1252  // }}}
1253  // {{{ Output : Xdg
1254 
1255  /* Future
1256  struct XdgOutput
1257  {
1258  std::string xdg_name;
1259  std::string xdg_description;
1260  int32_t xdg_logical_x;
1261  int32_t xdg_logical_y;
1262  int32_t xdg_logical_width;
1263  int32_t xdg_logical_height;
1264  };
1265 
1266  using MapXdgOutputData = std::unordered_map<OutputId, XdgOutput>;
1267 
1268  // -------------------------------------------------- //
1269 
1270  const MapOutputIdXdgOutput& xdgOutputMap() const noexcept;
1271  */
1272 
1273  // }}}
1274  // {{{ Shared Memory
1275 
1276  using VectorShmFormat = std::vector<wl_shm_format>;
1277 
1278  // -------------------------------------------------- //
1279 
1280  const Yetani::VectorShmFormat& shmFormatAvailable() const noexcept;
1281  static uint8_t shmFormatBytesPerPixel(const wl_shm_format) noexcept;
1282  static std::string shmFormatDescription(const wl_shm_format) noexcept;
1283  static std::string shmFormatName(const wl_shm_format) noexcept;
1284 
1285  // }}}
1286  // {{{ Window
1287 
1288  enum struct WindowDecorations
1289  { Client_Side
1290  , Server_Side
1291  };
1292 
1293  enum struct WindowMode
1294  { Normal
1295  , Fullscreen
1296  , Maximized
1297  };
1298 
1299  // -------------------------------------------------- //
1300 
1301  using Lambda = std::function<void()>;
1302  using LambdaKey = std::function<void(const Yetani::Key&, const Yetani::KeyModifier&)>;
1303  using LambdaAxis = std::function<void(const Yetani::PointerAxis&, const Yetani::KeyModifier&)>;
1304  using LambdaButtonMm = std::function<void(const Yetani::PointerButton&, const Yetani::PointMm&, const Yetani::KeyModifier&)>;
1305  using LambdaButtonPercent = std::function<void(const Yetani::PointerButton&, const Yetani::PointPercent&, const Yetani::KeyModifier&)>;
1306  using LambdaButtonPixel = std::function<void(const Yetani::PointerButton&, const Yetani::PointPixel&, const Yetani::KeyModifier&)>;
1307  using LambdaPointMm = std::function<void(const Yetani::PointMm&, const Yetani::KeyModifier&)>;
1308  using LambdaPointPercent = std::function<void(const Yetani::PointPercent&, const Yetani::KeyModifier&)>;
1309  using LambdaPointPixel = std::function<void(const Yetani::PointPixel&, const Yetani::KeyModifier&)>;
1310  using LambdaBool = std::function<void(bool)>;
1312  using LambdaWindowMode = std::function<void(Yetani::WindowMode)>;
1313  using LambdaSizeMm = std::function<void(const Yetani::SizeMm&)>;
1314  using LambdaSizePercent = std::function<void(const Yetani::SizePercent&)>;
1315  using LambdaSizePixel = std::function<void(const Yetani::SizePixel&)>;
1316 
1317  // -------------------------------------------------- //
1318 
1319  class Window
1320  {
1321  public:
1322  Window(void*);
1323  virtual ~Window();
1324 
1325  // {{{ Configuration
1326 
1327  void classSet(const std::string&) noexcept;
1328  void titleSet(const std::string&) noexcept;
1329 
1330  // }}}
1331  // {{{ Decorations
1332 
1333  std::error_code decorationsSet(const Yetani::WindowDecorations) noexcept;
1335 
1336  // }}}
1337  // {{{ Size
1338 
1339  std::error_code sizeSet(const Yetani::SizeMm&) noexcept;
1340  std::error_code sizeSet(const Yetani::SizePercent&) noexcept;
1341  std::error_code sizeSet(const Yetani::SizePixel&) noexcept;
1342  std::error_code sizeSetMinMax(const Yetani::SizeMm&, const Yetani::SizeMm&) noexcept;
1343  std::error_code sizeSetMinMax(const Yetani::SizePercent&, const Yetani::SizePercent&) noexcept;
1344  std::error_code sizeSetMinMax(const Yetani::SizePixel&, const Yetani::SizePixel&) noexcept;
1345  void sizeOnChange(Yetani::LambdaSizeMm) noexcept;
1346  void sizeOnChange(Yetani::LambdaSizePercent) noexcept;
1347  void sizeOnChange(Yetani::LambdaSizePixel) noexcept;
1348 
1349  // }}}
1350  // {{{ Window Mode
1351 
1352  Yetani::WindowMode windowMode() noexcept;
1353  bool windowModeIs(const Yetani::WindowMode) noexcept;
1354  void windowModeSet(const Yetani::WindowMode) noexcept;
1356 
1357  void minimize() noexcept;
1358 
1359  // }}}
1360  // {{{ Rendering
1361 
1362  std::error_code imageNext(uint8_t*&, Yetani::SizePixel&) noexcept;
1363  void imagePresent() noexcept;
1364  uint32_t time() const noexcept;
1365  uint8_t bytesPerPixel() const noexcept;
1366 
1367  // }}}
1368  // {{{ Conversion
1369 
1370  Yetani::PointMm convertToMm(const Yetani::PointPixel&) const noexcept;
1372  Yetani::PointPixel convertToPixel(const Yetani::PointMm&) const noexcept;
1374 
1375  Yetani::SizeMm convertToMm(const Yetani::SizePixel&) const noexcept;
1377  Yetani::SizePixel convertToPixel(const Yetani::SizeMm&) const noexcept;
1378  Yetani::SizePixel convertToPixel(const Yetani::SizePercent&) const noexcept;
1379 
1380  // }}}
1381  // {{{ Cursor
1382 
1383  std::error_code cursorUse(const std::string&) noexcept;
1384  void cursorHide() noexcept;
1385  void cursorShow() noexcept;
1386 
1387  // }}}
1388  // {{{ Keyboard
1389 
1390  void keyboardOnEnter(Yetani::Lambda) noexcept;
1391  void keyboardOnLeave(Yetani::Lambda) noexcept;
1392  void keyboardOnKey(Yetani::LambdaKey) noexcept;
1393 
1394  // }}}
1395  // {{{ Pointer
1396 
1397  void pointerOnAxis(Yetani::LambdaAxis) noexcept;
1398  void pointerOnButton(Yetani::LambdaButtonMm) noexcept;
1401  void pointerOnEnter(Yetani::LambdaPointMm) noexcept;
1404  void pointerOnLeave(Yetani::Lambda) noexcept;
1405  void pointerOnMotion(Yetani::LambdaPointMm) noexcept;
1408 
1409  // Not Used? Or Future?
1410  void pointerOnAxisSource(Yetani::Lambda) noexcept;
1411  void pointerOnAxisStop(Yetani::Lambda) noexcept;
1412  void pointerOnAxisDiscrete(Yetani::Lambda) noexcept;
1413 
1414  // }}}
1415  // {{{ Events
1416 
1417  void onCloseRequest(Yetani::Lambda) noexcept;
1418  void onFocusChange(Yetani::LambdaBool) noexcept;
1419 
1420  // }}}
1421 
1422  struct Memory
1423  {
1426  };
1427 
1428  private:
1429  Yetani* yetani;
1430  struct wl_buffer* wl_buffer;
1431  struct wl_surface* wl_surface;
1432  struct xdg_surface* xdg_surface;
1433  struct xdg_toplevel* xdg_toplevel;
1434  struct zxdg_toplevel_decoration_v1* xdg_decoration;
1435  Yetani::Window::Memory window_memory;
1436  wl_shm_format pixel_format;
1437 
1438  Window(const Window&) = delete;
1439  Window& operator=(const Window&) = delete;
1440  };
1441 
1442  // -------------------------------------------------- //
1443 
1444  static constexpr wl_shm_format SHM_FORMAT_DEFAULT = WL_SHM_FORMAT_XRGB8888;
1445 
1446  // -------------------------------------------------- //
1447 
1448  Yetani::Window* windowCreate(const Yetani::SizeMm&, std::error_code&) noexcept;
1449  Yetani::Window* windowCreate(const Yetani::SizeMm&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1450  Yetani::Window* windowCreate(const Yetani::SizeMm&, const wl_shm_format, std::error_code&) noexcept;
1451  Yetani::Window* windowCreate(const Yetani::SizePercent&, std::error_code&) noexcept;
1452  Yetani::Window* windowCreate(const Yetani::SizePercent&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1453  Yetani::Window* windowCreate(const Yetani::SizePercent&, const wl_shm_format, std::error_code&) noexcept;
1454  Yetani::Window* windowCreate(const Yetani::SizePixel&, std::error_code&) noexcept;
1455  Yetani::Window* windowCreate(const Yetani::SizePixel&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1456  Yetani::Window* windowCreate(const Yetani::SizePixel&, const wl_shm_format, std::error_code&) noexcept;
1457 
1458  // }}}
1459 
1460  private:
1461  static constexpr uint32_t Size_Max = (uint32_t)std::numeric_limits<int32_t>::max();
1462 
1463  Yetani() noexcept;
1464 
1465  // {{{ Type
1466 
1467  using VectorWlSurface = std::vector<struct wl_surface*>;
1468 
1469  // }}}
1470  // {{{ Connection
1471 
1472  void disconnect() noexcept;
1473 
1474  // }}}
1475  // {{{ Cursor
1476 
1477  struct Cursor
1478  {
1479  struct wl_surface* wl_surface = nullptr;
1480  std::vector<::wl_buffer*> buffer_vector = {};
1481  wl_shm_format format = WL_SHM_FORMAT_ARGB8888;
1482  int64_t next_frame_time = 0;
1483  size_t buffer_index = 0;
1484  uint32_t time_per_frame = 0;
1485  int32_t width = 0;
1486  int32_t height = 0;
1487  int32_t hotspot_x = 0;
1488  int32_t hotspot_y = 0;
1489  };
1490 
1491  using MapStringCursor = std::unordered_map<std::string, Yetani::Cursor>;
1492 
1493  MapStringCursor cursor_map;
1494 
1495  // -------------------------------------------------- //
1496 
1497  struct CursorSurface
1498  {
1499  struct wl_pointer* wl_pointer;
1500  struct wl_surface* wl_surface;
1501  uint32_t serial;
1502  int32_t hotspot_x;
1503  int32_t hotspot_y;
1504  bool is_visible;
1505  };
1506 
1507  using MapCursorSurface = std::unordered_map<struct wl_surface*, Yetani::CursorSurface>;
1508 
1509  MapCursorSurface cursor_surface_map;
1510 
1511  // -------------------------------------------------- //
1512 
1513  zakero::MemoryPool cursor_memory_pool;
1514  mutable std::mutex cursor_mutex;
1515  struct wl_shm_pool* cursor_shm_pool;
1516  struct wl_pointer* cursor_pointer;
1517 
1518  // -------------------------------------------------- //
1519 
1520  void cursorAnimate() noexcept;
1521  std::error_code cursorCreateCursor(const std::string&, const Yetani::CursorConfig&) noexcept;
1522  void cursorEnter(struct wl_pointer*, uint32_t, struct wl_surface*) noexcept;
1523  void cursorLeave(struct wl_surface*) noexcept;
1524  void cursorHide(struct wl_surface*) noexcept;
1525  void cursorShow(struct wl_surface*) noexcept;
1526  bool cursorIsHidden(struct wl_surface*) const noexcept;
1527  void cursorSetup() noexcept;
1528  void cursorTeardown() noexcept;
1529  std::error_code cursorAttach(const std::string&, struct wl_surface*) noexcept;
1530  std::error_code cursorDetach(struct wl_surface*) noexcept;
1531 
1532  // }}}
1533  // {{{ Event Loop
1534 
1535  std::jthread event_loop;
1536  std::atomic<bool> event_loop_is_running;
1537 
1538  // -------------------------------------------------- //
1539 
1540  void eventLoopStart() noexcept;
1541  static void eventLoop(std::stop_token, Yetani*) noexcept;
1542 
1543  // }}}
1544  // {{{ Wayland
1545 
1546  struct wl_compositor* compositor;
1547  struct wl_display* display;
1548  struct wl_registry* registry;
1549  struct wl_shm* shm;
1550  Yetani::VectorShmFormat shm_format_vector;
1551 
1552  // }}}
1553  // {{{ Wayland : Seat
1554 
1555  struct Seat
1556  {
1557  struct wl_keyboard* wl_keyboard = nullptr;
1558  struct wl_pointer* wl_pointer = nullptr;
1559  struct wl_touch* wl_touch = nullptr;
1560  std::string name = "";
1561  uint32_t version = 0;
1562  };
1563 
1564  using MapSeat = std::map<struct wl_seat*, Seat>;
1565  using MapIdWlSeat = std::map<uint32_t, struct wl_seat*>;
1566 
1567  Yetani::MapSeat seat_map;
1568  Yetani::MapIdWlSeat id_to_seat;
1569 
1570  // -------------------------------------------------- //
1571 
1572  struct wl_seat* seat;
1573 
1574  // -------------------------------------------------- //
1575 
1576  void seatDestroy(struct wl_seat*&) noexcept;
1577 
1578  // }}}
1579  // {{{ Wayland : Seat : Keyboard
1580 
1581  struct KeyRepeatData
1582  {
1583  std::chrono::time_point<std::chrono::steady_clock> trigger_time = {};
1584  uint32_t base_time = 0;
1585  };
1586 
1587  using KeyRepeatMap = std::map<uint32_t, Yetani::KeyRepeatData>;
1588 
1589  // -------------------------------------------------- //
1590 
1591  struct KeyboardEvent
1592  {
1593  Yetani::Lambda on_enter = {};
1594  Yetani::Lambda on_leave = {};
1595  Yetani::LambdaKey on_key = {};
1596  };
1597 
1598  using MapKeyboardEvent = std::unordered_map<struct wl_surface*, Yetani::KeyboardEvent>;
1599 
1600  // -------------------------------------------------- //
1601 
1602  struct Keyboard
1603  {
1604  struct wl_surface* wl_surface = nullptr;
1605  Yetani::KeyboardEvent* event = nullptr;
1606  Yetani::MapKeyboardEvent event_map = {};
1607  Yetani::KeyModifier modifier = {};
1608  Yetani::KeyRepeatMap repeat_map = {};
1609  char* keymap = nullptr;
1610  uint32_t keymap_size = 0;
1611  int32_t repeat_delay = 0;
1612  int32_t repeat_rate = 0;
1613  };
1614 
1615  Yetani::Keyboard keyboard;
1616 
1617  // -------------------------------------------------- //
1618 
1619  static void keyboardDestroy(Yetani::Keyboard&) noexcept;
1620  static void keyboardRepeat(Yetani::Keyboard&) noexcept;
1621  static void keyboardRepeatAdd(Yetani::Keyboard&, uint32_t, uint32_t) noexcept;
1622  static void keyboardRepeatReleaseAll(Yetani::Keyboard&) noexcept;
1623  static void keyboardRepeatRemove(Yetani::Keyboard&, uint32_t) noexcept;
1624 
1625  // }}}
1626  // {{{ Wayland : Seat : Pointer
1627 
1628  struct PointerEvent
1629  {
1630  Yetani::LambdaAxis on_axis = {};
1631  Yetani::Lambda on_axis_discrete = {};
1632  Yetani::Lambda on_axis_source = {};
1633  Yetani::Lambda on_axis_stop = {};
1634  Yetani::LambdaButtonMm on_button_mm = {};
1635  Yetani::LambdaButtonPercent on_button_percent = {};
1636  Yetani::LambdaButtonPixel on_button_pixel = {};
1637  Yetani::LambdaPointMm on_enter_mm = {};
1638  Yetani::LambdaPointPercent on_enter_percent = {};
1639  Yetani::LambdaPointPixel on_enter_pixel = {};
1640  Yetani::Lambda on_leave = {};
1641  Yetani::LambdaPointMm on_motion_mm = {};
1642  Yetani::LambdaPointPercent on_motion_percent = {};
1643  Yetani::LambdaPointPixel on_motion_pixel = {};
1644  };
1645 
1646  using MapPointerEvent = std::unordered_map<struct wl_surface*, Yetani::PointerEvent>;
1647 
1648  // -------------------------------------------------- //
1649 
1650  struct Pointer
1651  {
1652  // --- Common --- //
1653  Yetani* yetani = nullptr;
1654  struct wl_surface* wl_surface = nullptr;
1655  struct wl_pointer* wl_pointer = nullptr;
1656  Yetani::PointerEvent* event = nullptr;
1657  Yetani::MapPointerEvent event_map = {};
1658 
1659  // --- Processed Data --- //
1660  Yetani::PointMm point_mm = {};
1661  Yetani::PointPercent point_percent = {};
1662  Yetani::PointPixel point_pixel = {};
1663 
1664  // --- Axis --- //
1665  Yetani::PointerAxis axis = {};
1666 
1667  // --- Button --- //
1668  Yetani::PointerButton button = {};
1669  uint32_t button_event_code = 0;
1670  bool button_is_pressed = false;
1671  uint32_t button_time = {};
1672 
1673  // --- Enter --- //
1674  struct wl_surface* enter_surface = nullptr;
1675  Yetani::PointPixel enter_point = {};
1676  uint32_t enter_serial = 0;
1677 
1678  // --- Leave --- //
1679  struct wl_surface* leave_surface = nullptr;
1680 
1681  // --- Motion --- //
1682  Yetani::PointPixel motion_point = {};
1683  };
1684 
1685  Yetani::Pointer pointer;
1686 
1687  // -------------------------------------------------- //
1688 
1689  static void pointerClear(struct Pointer&) noexcept;
1690 
1691  // }}}
1692  // {{{ Wayland : Output
1693 
1694  enum struct OutputState
1695  { Done
1696  , Added
1697  , Changed
1698  };
1699 
1700  // -------------------------------------------------- //
1701 
1702  using VectorWlOutput = std::vector<struct wl_output*>;
1703 
1704  using MapWlOutputOutputState = std::unordered_map<struct wl_output*, Yetani::OutputState>;
1705  using MapOutputIdWlOutput = std::unordered_map<Yetani::OutputId, struct wl_output*>;
1706  using MapWlOutputOutputId = std::unordered_map<struct wl_output*, Yetani::OutputId>;
1707  using MapWlSurfaceVectorWlOutput = std::unordered_map<struct wl_surface*, Yetani::VectorWlOutput>;
1708  using MapWlOutputOutput = std::unordered_map<struct wl_output*, Output>;
1709 
1710  // -------------------------------------------------- //
1711 
1712  struct OutputData
1713  {
1714  Yetani::MapWlSurfaceVectorWlOutput surface_output_map = {};
1715  Yetani::MapOutputIdWlOutput outputid_to_wloutput = {};
1716  Yetani::MapWlOutputOutput output_map = {};
1717  Yetani::MapWlOutputOutputId wloutput_to_outputid = {};
1718  mutable std::mutex mutex = {};
1719  };
1720 
1721  Yetani::OutputData output_data;
1722 
1723  // -------------------------------------------------- //
1724 
1725  Yetani::LambdaOutputId on_output_add;
1726  Yetani::LambdaOutputId on_output_change;
1727  Yetani::LambdaOutputId on_output_remove;
1728 
1729  Yetani::MapWlOutputOutput output_changes_map;
1730  Yetani::MapWlOutputOutputState output_state_map;
1731 
1732  Yetani::VectorWlSurface output_notify_surface_vector;
1733 
1734  // -------------------------------------------------- //
1735 
1736  void convertPixel(struct wl_surface*, const int32_t, const int32_t, float&, float&, float&, float&) const noexcept;
1737 
1738  std::pair<float, float> convertPixelToMm(const Yetani::Output&, int32_t, int32_t) const noexcept;
1739  std::pair<float, float> convertPixelToPercent(const Yetani::Output&, int32_t, int32_t) const noexcept;
1740  std::pair<int32_t, int32_t> convertMmToPixel(const Yetani::Output&, float, float) const noexcept;
1741  std::pair<int32_t, int32_t> convertPercentToPixel(const Yetani::Output&, float, float) const noexcept;
1742 
1743  static void outputNotifySurface(Yetani*, struct wl_output*, struct wl_surface*) noexcept;
1744 
1745  // }}}
1746  // {{{ Wayland : Buffer
1747 
1748  struct SurfaceSize;
1749 
1750  struct BufferData
1751  {
1752  MemoryPool* memory_pool = nullptr;
1753  off_t offset = 0;
1754  };
1755 
1756  using MapBufferData = std::unordered_map<struct wl_buffer*, BufferData>;
1757 
1758  // -------------------------------------------------- //
1759 
1760  struct Buffer
1761  {
1762  MapBufferData map = {};
1763  std::mutex mutex = {};
1764  };
1765 
1766  Buffer buffer;
1767 
1768  // -------------------------------------------------- //
1769 
1770  static wl_buffer* bufferCreate(Yetani::SurfaceSize&, Yetani::Window::Memory*, Yetani::Buffer*) noexcept;
1771  static void bufferDestroy(struct wl_buffer*&) noexcept;
1772 
1773  // }}}
1774  // {{{ Wayland : Surface
1775 
1776  struct SurfaceEvent
1777  {
1778  Yetani::LambdaSizeMm on_size_mm_change = {};
1779  Yetani::LambdaSizePercent on_size_percent_change = {};
1780  Yetani::LambdaSizePixel on_size_pixel_change = {};
1781  };
1782 
1783  using MapSurfaceEvent = std::map<struct wl_surface*, Yetani::SurfaceEvent>;
1784 
1785  MapSurfaceEvent surface_event_map;
1786 
1787  // -------------------------------------------------- //
1788 
1789  enum struct SizeUnit
1790  { Millimeter
1791  , Percent
1792  , Pixel
1793  };
1794 
1795  // This is the data that needs to be locked from resizing
1796  // Use mainly by XdgSurface related methods
1797  struct SurfaceExtent
1798  {
1799  Yetani::SizeUnit preferred_unit = {};
1800  Yetani::SizeMm preferred_mm = {};
1801  Yetani::SizePercent preferred_percent = {};
1802  Yetani::SizeMm size_mm = {};
1803  Yetani::SizePercent size_percent = {};
1804  Yetani::SizePixel size_pixel = {};
1805  Yetani::SizePixel size_pixel_max = {};
1806  Yetani::SizePixel size_pixel_min = {};
1807  };
1808 
1809  using MapSurfaceExtent = std::unordered_map<struct wl_surface*, Yetani::SurfaceExtent>;
1810 
1811  MapSurfaceExtent surface_extent_map;
1812  std::mutex surface_extent_mutex; // For surface adding and removing
1813 
1814  // -------------------------------------------------- //
1815 
1816  struct SurfaceFrame
1817  {
1818  struct wl_surface* wl_surface = nullptr;
1819  std::atomic<wl_buffer*> buffer_next = {};
1820  uint32_t width = 0;
1821  uint32_t height = 0;
1822  uint32_t time_ms = 0;
1823  };
1824 
1825  using MapSurfaceFrame = std::unordered_map<struct wl_surface*, Yetani::SurfaceFrame>;
1826 
1827  MapSurfaceFrame surface_frame_map;
1828 
1829  // -------------------------------------------------- //
1830 
1831  struct SurfaceSize
1832  {
1833  int32_t width;
1834  int32_t height;
1835  int32_t stride;
1836  uint32_t in_bytes;
1837  wl_shm_format pixel_format;
1838  uint8_t bytes_per_pixel;
1839  };
1840 
1841  using MapSurfaceSize = std::unordered_map<struct wl_surface*, Yetani::SurfaceSize>;
1842 
1843  MapSurfaceSize surface_size_map;
1844 
1845  // -------------------------------------------------- //
1846 
1847  using MapSurfaceResizeMutex = std::unordered_map<struct wl_surface*, std::mutex>;
1848 
1849  MapSurfaceResizeMutex surface_resize_mutex_map;
1850 
1851  // -------------------------------------------------- //
1852 
1853  static void surfaceCalculateSize(Yetani*, struct wl_surface*, const Yetani::SizePixel&) noexcept;
1854  static struct wl_surface* surfaceCreate(Yetani*, const wl_shm_format, const Yetani::SizePixel&, Yetani::Window::Memory&) noexcept;
1855  static void surfaceDestroy(Yetani*, struct wl_surface*&) noexcept;
1856 
1857  // }}}
1858  // {{{ Window
1859 
1860  struct WindowData
1861  {
1862  Yetani* yetani;
1863  struct wl_shm* wl_shm;
1864  struct wl_output* wl_output;
1865  std::string file_name;
1866  Yetani::SizeMm size_mm;
1867  Yetani::SizePercent size_percent;
1868  Yetani::SizePixel size_pixel;
1869  Yetani::SizeUnit size_unit;
1870  wl_shm_format pixel_format;
1871  std::error_code error;
1872  };
1873 
1874  // -------------------------------------------------- //
1875 
1876  Yetani::Window* windowCreate(const Yetani::SizeUnit, const Yetani::SizeMm&, const Yetani::SizePercent&, const Yetani::SizePixel&, const wl_shm_format, std::error_code&) noexcept;
1877  void windowDataInit(Yetani::WindowData&) noexcept;
1878  void windowDataInitOutput(Yetani::WindowData&) noexcept;
1879  void windowInitMemory(Yetani::WindowData&, Yetani::Window::Memory&) noexcept;
1880  void windowInitOutput(Yetani::WindowData&, struct wl_surface*) noexcept;
1881  void windowEraseMemory(Yetani::Window::Memory&) noexcept;
1882  void windowEraseOutput(struct wl_surface*) noexcept;
1883  void windowEraseSurfaceExtent(struct wl_surface*) noexcept;
1884 
1885  // }}}
1886  // {{{ Utility
1887 
1888  std::vector<Yetani::Window*> window_vector;
1889  std::mutex window_vector_mutex;
1890 
1891  // -------------------------------------------------- //
1892 
1893  void windowAdd(Yetani::Window*) noexcept;
1894  void windowRemove(Yetani::Window*) noexcept;
1895 
1896  // }}}
1897  // {{{ XDG
1898 
1899  enum XdgState : int32_t
1900  { Unknown = 0
1901  , Toplevel_Active = 1
1902  , Toplevel_Attach_Buffer = 2
1903  , Toplevel_Resizing = 3
1904  , Toplevel_Window_Fullscreen = 4
1905  , Toplevel_Window_Maximized = 5
1906  , Toplevel_Window_Normal = 6
1907  , Toplevel_Decoration = 7
1908  };
1909 
1910  using VectorXdgStateChange = std::vector<int32_t>;
1911  using MapXdgStateChange = std::unordered_map<struct xdg_surface*, Yetani::VectorXdgStateChange>;
1912 
1913  Yetani::MapXdgStateChange xdg_state_change_map;
1914  std::mutex xdg_state_change_mutex;
1915 
1916  // -------------------------------------------------- //
1917 
1918  struct xdg_wm_base* xdg_wm_base;
1919 
1920  // -------------------------------------------------- //
1921 
1922  static Yetani::WindowMode toWindowMode(const Yetani::XdgState) noexcept;
1923  static Yetani::XdgState toXdgState(const Yetani::WindowMode) noexcept;
1924 
1925  // }}}
1926  // {{{ XDG : Surface
1927 
1928  struct XdgSurface
1929  {
1930  Yetani* yetani = nullptr;
1931  struct wl_surface* wl_surface = nullptr;
1932  };
1933 
1934  using MapXdgSurface = std::unordered_map<struct wl_surface*, Yetani::XdgSurface>;
1935 
1936  Yetani::MapXdgSurface xdg_surface_map;
1937 
1938  // -------------------------------------------------- //
1939 
1940  struct xdg_surface* xdgSurfaceCreate(struct wl_surface*) noexcept;
1941  void xdgSurfaceDestroy(struct wl_surface*, struct xdg_surface*&) noexcept;
1942  void xdgSurfaceSetExtent(struct wl_surface*, const Yetani::SizeUnit&, const Yetani::SizeMm&, const Yetani::SizePercent&, const Yetani::SizePixel&) noexcept;
1943 
1944  // }}}
1945  // {{{ XDG : Toplevel
1946 
1947  struct XdgToplevel
1948  {
1949  Yetani::VectorXdgStateChange* state_change = nullptr;
1950  Yetani::Lambda close_request_lambda = {};
1951  Yetani::LambdaBool is_active_lambda = {};
1952  bool is_active = false;
1953  Yetani::XdgState window_state = XdgState::Unknown;
1954  Yetani::LambdaWindowMode window_state_lambda = {};
1955  Yetani::SizePixel previous_size = {};
1956  struct xdg_toplevel* xdg_toplevel = nullptr;
1957  };
1958 
1959  using MapXdgToplevel = std::unordered_map<struct xdg_surface*, Yetani::XdgToplevel>;
1960 
1961  MapXdgToplevel xdg_toplevel_map;
1962 
1963  // -------------------------------------------------- //
1964 
1965  struct xdg_toplevel* xdgToplevelCreate(struct xdg_surface*) noexcept;
1966  void xdgToplevelDestroy(struct xdg_surface*, struct xdg_toplevel*&) noexcept;
1967  static void xdgToplevelSizeChange(Yetani*, struct wl_surface*, const Yetani::SizePixel&) noexcept;
1968  static void xdgToplevelSizeMinMaxChange(Yetani*, struct xdg_toplevel*, struct wl_surface*, const Yetani::SizePixel&, const Yetani::SizePixel&) noexcept;
1969  static void xdgToplevelWindowChange(Yetani*, struct wl_surface*, Yetani::XdgToplevel&, const Yetani::XdgState, const Yetani::SizePixel&) noexcept;
1970 
1971  // }}}
1972  // {{{ XDG : Decoration Manager (Unstable)
1973 
1974  struct XdgDecoration
1975  {
1976  Yetani::VectorXdgStateChange* state_change = nullptr;
1977  Yetani::LambdaWindowDecorations lambda = {};
1978  uint32_t state = 0;
1979  bool is_present = false;
1980  //struct zxdg_toplevel_decoration_v1* xdg_decoration;
1981  };
1982 
1983  using MapXdgDecoration = std::unordered_map<struct xdg_surface*, Yetani::XdgDecoration>;
1984 
1985  MapXdgDecoration xdg_decoration_map;
1986 
1987  // -------------------------------------------------- //
1988 
1989  struct zxdg_decoration_manager_v1* decoration_manager;
1990 
1991  // -------------------------------------------------- //
1992 
1993  struct zxdg_toplevel_decoration_v1* xdgDecorationCreate(struct xdg_surface*, struct xdg_toplevel*) noexcept;
1994  void xdgDecorationDestroy(struct xdg_surface*, struct xdg_toplevel*, struct zxdg_toplevel_decoration_v1*&) noexcept;
1995  static void xdgDecorationChange(Yetani::XdgDecoration&, const uint32_t) noexcept;
1996 
1997  // }}}
1998  // {{{ Listener Handlers : Wayland
1999 
2000  static struct wl_buffer_listener buffer_listener;
2001  static struct wl_callback_listener frame_callback_listener;
2002  static struct wl_keyboard_listener keyboard_listener;
2003  static struct wl_output_listener output_listener;
2004  static struct wl_pointer_listener pointer_listener;
2005  static struct wl_registry_listener registry_listener;
2006  static struct wl_seat_listener seat_listener;
2007  static struct wl_shm_listener shm_listener;
2008  static struct wl_surface_listener surface_listener;
2009 
2010  // -------------------------------------------------- //
2011 
2012  static void handlerBufferRelease(void*, struct wl_buffer*) noexcept;
2013 
2014  static void handlerKeyboardEnter(void*, struct wl_keyboard*, uint32_t, struct wl_surface*, struct wl_array*) noexcept;
2015  static void handlerKeyboardKey(void*, struct wl_keyboard*, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
2016  static void handlerKeyboardKeymap(void*, struct wl_keyboard*, uint32_t, int32_t, uint32_t) noexcept;
2017  static void handlerKeyboardLeave(void*, struct wl_keyboard*, uint32_t, struct wl_surface*) noexcept;
2018  static void handlerKeyboardModifiers(void*, struct wl_keyboard*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
2019  static void handlerKeyboardRepeatInfo(void*, struct wl_keyboard*, int32_t, int32_t) noexcept;
2020 
2021  static void handlerOutputDone(void*, struct wl_output*) noexcept;
2022  static void handlerOutputGeometry(void*, struct wl_output*, int32_t, int32_t, int32_t, int32_t, int32_t, const char*, const char*, int32_t) noexcept;
2023  static void handlerOutputMode(void*, struct wl_output*, uint32_t, int32_t, int32_t, int32_t) noexcept;
2024  static void handlerOutputScale(void*, struct wl_output*, int32_t) noexcept;
2025  static void handlerPointerAxis(void*, struct wl_pointer*, uint32_t, uint32_t, wl_fixed_t) noexcept;
2026  static void handlerPointerAxisDiscrete(void*, struct wl_pointer*, uint32_t, int32_t) noexcept;
2027  static void handlerPointerAxisSource(void*, struct wl_pointer*, uint32_t) noexcept;
2028  static void handlerPointerAxisStop(void*, struct wl_pointer*, uint32_t, uint32_t) noexcept;
2029  static void handlerPointerButton(void*, struct wl_pointer*, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
2030  static void handlerPointerEnter(void*, struct wl_pointer*, uint32_t, struct wl_surface*, wl_fixed_t, wl_fixed_t) noexcept;
2031  static void handlerPointerFrame(void*, struct wl_pointer*) noexcept;
2032  static void handlerPointerLeave(void*, struct wl_pointer*, uint32_t, struct wl_surface*) noexcept;
2033  static void handlerPointerMotion(void*, struct wl_pointer*, uint32_t, wl_fixed_t, wl_fixed_t) noexcept;
2034  static void handlerRegistryGlobal(void*, struct wl_registry*, uint32_t, const char*, uint32_t) noexcept;
2035  static void handlerRegistryRemove(void*, struct wl_registry*, uint32_t) noexcept;
2036  static void handlerSeatCapabilities(void*, struct wl_seat*, uint32_t) noexcept;
2037  static void handlerSeatName(void*, struct wl_seat*, const char*) noexcept;
2038  static void handlerShmFormat(void*, struct wl_shm*, uint32_t) noexcept;
2039  static void handlerSurfaceEnter(void*, struct wl_surface*, struct wl_output*) noexcept;
2040  static void handlerSurfaceLeave(void*, struct wl_surface*, struct wl_output*) noexcept;
2041  static void handlerSwapBuffers(void*, struct wl_callback*, uint32_t) noexcept;
2042 
2043  // }}}
2044  // {{{ Listener Handlers : Wayland Unstable
2045  // }}}
2046  // {{{ Listener Handlers : XDG
2047 
2048  static struct xdg_wm_base_listener xdg_wm_base_listener;
2049  static struct xdg_surface_listener xdg_surface_listener;
2050  static struct xdg_toplevel_listener xdg_toplevel_listener;
2051 
2052  // -------------------------------------------------- //
2053 
2054  static void handlerXdgSurfaceConfigure(void*, struct xdg_surface*, uint32_t) noexcept;
2055  static void handlerXdgToplevelClose(void*, struct xdg_toplevel*) noexcept;
2056  static void handlerXdgToplevelConfigure(void*, struct xdg_toplevel*, int32_t, int32_t, struct wl_array*) noexcept;
2057  static void handlerXdgWmBasePing(void*, struct xdg_wm_base*, uint32_t) noexcept;
2058 
2059  // }}}
2060  // {{{ Listener Handlers : XDG Unstable
2061 
2062  static struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener;
2063 
2064  // -------------------------------------------------- //
2065 
2066  static void handlerXdgToplevelDecorationConfigure(void*, struct zxdg_toplevel_decoration_v1*, uint32_t mode) noexcept;
2067 
2068  // }}}
2069 
2070  Yetani(const Yetani&) = delete;
2071  Yetani& operator=(const Yetani&) = delete;
2072  }; // class Yetani
2073 
2074  // }}}
2075  // {{{ Convenience
2076 
2077  std::string to_string(const wl_shm_format&) noexcept;
2078  std::string to_string(const std::error_code&) noexcept;
2079  std::string to_string(const Yetani::Key&) noexcept;
2080  std::string to_string(const Yetani::KeyModifier&) noexcept;
2081  std::string to_string(const Yetani::KeyState&) noexcept;
2082  std::string to_string(const Yetani::Output&) noexcept;
2083  std::string to_string(const Yetani::PointMm&) noexcept;
2084  std::string to_string(const Yetani::PointPercent&) noexcept;
2085  std::string to_string(const Yetani::PointPixel&) noexcept;
2086  std::string to_string(const Yetani::PointerAxis&) noexcept;
2087  std::string to_string(const Yetani::PointerAxisSource&) noexcept;
2088  std::string to_string(const Yetani::PointerAxisType&) noexcept;
2089  std::string to_string(const Yetani::PointerButtonState&) noexcept;
2090  std::string to_string(const Yetani::WindowMode&) noexcept;
2091 
2092  // }}}
2093 }
2094 
2095 // {{{ Implementation
2096 
2097 #ifdef ZAKERO_YETANI_IMPLEMENTATION
2098 
2099 // {{{ Macros
2100 
2101 // {{{ Macros : Doxygen
2102 
2103 #ifdef ZAKERO__DOXYGEN_DEFINE_DOCS
2104 
2105 // Only used for generating Doxygen documentation
2106 
2118 #define ZAKERO_YETANI_IMPLEMENTATION
2119 
2128 #define ZAKERO_YETANI_ENABLE_DEBUG
2129 
2138 #define ZAKERO_YETANI_ENABLE_SAFE_MODE
2139 
2140 #endif // ZAKERO__DOXYGEN_DEFINE_DOCS
2141 
2142 // }}}
2143 
2159 #ifdef ZAKERO_YETANI_ENABLE_DEBUG
2160 #define ZAKERO_YETANI__DEBUG_DISABLED false
2161 #else
2162 #define ZAKERO_YETANI__DEBUG_DISABLED true
2163 #endif
2164 
2165 
2178 #ifndef ZAKERO_YETANI_ENABLE_DEBUG_STREAM
2179 #define ZAKERO_YETANI_ENABLE_DEBUG_STREAM std::cerr
2180 #endif
2181 
2182 
2200 #define ZAKERO_YETANI__DEBUG \
2201  if(ZAKERO_YETANI__DEBUG_DISABLED) {} \
2202  else ZAKERO_YETANI_ENABLE_DEBUG_STREAM \
2203  << __FILE__"(" \
2204  << std::to_string(__LINE__) \
2205  << ") " \
2206  << __PRETTY_FUNCTION__ \
2207  << " "
2208 
2225 #define ZAKERO_YETANI__DEBUG_VAR(var_) \
2226  ZAKERO_YETANI__DEBUG \
2227  << #var_ << ": " << var_ \
2228  << "\n";
2229 
2245 #define ZAKERO_YETANI__DEBUG_BOOL(var_) \
2246  ZAKERO_YETANI__DEBUG \
2247  << #var_ << ": " << std::boolalpha << var_ \
2248  << "\n";
2249 
2260 #define ZAKERO_YETANI__ERROR(err_) std::error_code(err_, YetaniErrorCategory)
2261 
2262 
2279 #define ZAKERO_YETANI__SHM_FORMAT \
2280  X(WL_SHM_FORMAT_ARGB8888 , 4 , "32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian" ) \
2281  X(WL_SHM_FORMAT_XRGB8888 , 4 , "32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian" ) \
2282  X(WL_SHM_FORMAT_C8 , 1 , "8-bit color index format, [7:0] C" ) \
2283  X(WL_SHM_FORMAT_RGB332 , 1 , "8-bit RGB format, [7:0] R:G:B 3:3:2" ) \
2284  X(WL_SHM_FORMAT_BGR233 , 1 , "8-bit BGR format, [7:0] B:G:R 2:3:3" ) \
2285  X(WL_SHM_FORMAT_XRGB4444 , 2 , "16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian" ) \
2286  X(WL_SHM_FORMAT_XBGR4444 , 2 , "16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian" ) \
2287  X(WL_SHM_FORMAT_RGBX4444 , 2 , "16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian" ) \
2288  X(WL_SHM_FORMAT_BGRX4444 , 2 , "16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian" ) \
2289  X(WL_SHM_FORMAT_ARGB4444 , 2 , "16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian" ) \
2290  X(WL_SHM_FORMAT_ABGR4444 , 2 , "16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian" ) \
2291  X(WL_SHM_FORMAT_RGBA4444 , 2 , "16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian" ) \
2292  X(WL_SHM_FORMAT_BGRA4444 , 2 , "16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian" ) \
2293  X(WL_SHM_FORMAT_XRGB1555 , 2 , "16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian" ) \
2294  X(WL_SHM_FORMAT_XBGR1555 , 2 , "16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian" ) \
2295  X(WL_SHM_FORMAT_RGBX5551 , 2 , "16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian" ) \
2296  X(WL_SHM_FORMAT_BGRX5551 , 2 , "16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian" ) \
2297  X(WL_SHM_FORMAT_ARGB1555 , 2 , "16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian" ) \
2298  X(WL_SHM_FORMAT_ABGR1555 , 2 , "16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian" ) \
2299  X(WL_SHM_FORMAT_RGBA5551 , 2 , "16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian" ) \
2300  X(WL_SHM_FORMAT_BGRA5551 , 2 , "16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian" ) \
2301  X(WL_SHM_FORMAT_RGB565 , 2 , "16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian" ) \
2302  X(WL_SHM_FORMAT_BGR565 , 2 , "16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian" ) \
2303  X(WL_SHM_FORMAT_RGB888 , 3 , "24-bit RGB format, [23:0] R:G:B little endian" ) \
2304  X(WL_SHM_FORMAT_BGR888 , 3 , "24-bit BGR format, [23:0] B:G:R little endian" ) \
2305  X(WL_SHM_FORMAT_XBGR8888 , 4 , "32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian" ) \
2306  X(WL_SHM_FORMAT_RGBX8888 , 4 , "32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian" ) \
2307  X(WL_SHM_FORMAT_BGRX8888 , 4 , "32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian" ) \
2308  X(WL_SHM_FORMAT_ABGR8888 , 4 , "32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian" ) \
2309  X(WL_SHM_FORMAT_RGBA8888 , 4 , "32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian" ) \
2310  X(WL_SHM_FORMAT_BGRA8888 , 4 , "32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian" ) \
2311  X(WL_SHM_FORMAT_XRGB2101010 , 4 , "32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian" ) \
2312  X(WL_SHM_FORMAT_XBGR2101010 , 4 , "32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian" ) \
2313  X(WL_SHM_FORMAT_RGBX1010102 , 4 , "32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian" ) \
2314  X(WL_SHM_FORMAT_BGRX1010102 , 4 , "32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian" ) \
2315  X(WL_SHM_FORMAT_ARGB2101010 , 4 , "32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian" ) \
2316  X(WL_SHM_FORMAT_ABGR2101010 , 4 , "32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian" ) \
2317  X(WL_SHM_FORMAT_RGBA1010102 , 4 , "32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian" ) \
2318  X(WL_SHM_FORMAT_BGRA1010102 , 4 , "32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian" ) \
2319  X(WL_SHM_FORMAT_YUYV , 4 , "packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian" ) \
2320  X(WL_SHM_FORMAT_YVYU , 4 , "packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian" ) \
2321  X(WL_SHM_FORMAT_UYVY , 4 , "packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian" ) \
2322  X(WL_SHM_FORMAT_VYUY , 4 , "packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian" ) \
2323  X(WL_SHM_FORMAT_AYUV , 4 , "packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian" ) \
2324  X(WL_SHM_FORMAT_NV12 , 8 , "2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane" ) \
2325  X(WL_SHM_FORMAT_NV21 , 8 , "2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane" ) \
2326  X(WL_SHM_FORMAT_NV16 , 8 , "2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane" ) \
2327  X(WL_SHM_FORMAT_NV61 , 8 , "2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane" ) \
2328  X(WL_SHM_FORMAT_YUV410 , 8 , "3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes" ) \
2329  X(WL_SHM_FORMAT_YVU410 , 8 , "3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes" ) \
2330  X(WL_SHM_FORMAT_YUV411 , 8 , "3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes" ) \
2331  X(WL_SHM_FORMAT_YVU411 , 8 , "3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes" ) \
2332  X(WL_SHM_FORMAT_YUV420 , 8 , "3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes" ) \
2333  X(WL_SHM_FORMAT_YVU420 , 8 , "3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes" ) \
2334  X(WL_SHM_FORMAT_YUV422 , 8 , "3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes" ) \
2335  X(WL_SHM_FORMAT_YVU422 , 8 , "3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes" ) \
2336  X(WL_SHM_FORMAT_YUV444 , 8 , "3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes" ) \
2337  X(WL_SHM_FORMAT_YVU444 , 8 , "3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes" ) \
2338  X(WL_SHM_FORMAT_R8 , 1 , "[7:0] R" ) \
2339  X(WL_SHM_FORMAT_R16 , 2 , "[15:0] R little endian" ) \
2340  X(WL_SHM_FORMAT_RG88 , 2 , "[15:0] R:G 8:8 little endian" ) \
2341  X(WL_SHM_FORMAT_GR88 , 2 , "[15:0] G:R 8:8 little endian" ) \
2342  X(WL_SHM_FORMAT_RG1616 , 4 , "[31:0] R:G 16:16 little endian" ) \
2343  X(WL_SHM_FORMAT_GR1616 , 4 , "[31:0] G:R 16:16 little endian" ) \
2344  X(WL_SHM_FORMAT_XRGB16161616F , 8 , "[63:0] x:R:G:B 16:16:16:16 little endian" ) \
2345  X(WL_SHM_FORMAT_XBGR16161616F , 8 , "[63:0] x:B:G:R 16:16:16:16 little endian" ) \
2346  X(WL_SHM_FORMAT_ARGB16161616F , 8 , "[63:0] A:R:G:B 16:16:16:16 little endian" ) \
2347  X(WL_SHM_FORMAT_ABGR16161616F , 8 , "[63:0] A:B:G:R 16:16:16:16 little endian" ) \
2348  X(WL_SHM_FORMAT_XYUV8888 , 4 , "[31:0] X:Y:Cb:Cr 8:8:8:8 little endian" ) \
2349  X(WL_SHM_FORMAT_VUY888 , 3 , "[23:0] Cr:Cb:Y 8:8:8 little endian" ) \
2350  X(WL_SHM_FORMAT_VUY101010 , 4 , "Y followed by U then V, 10:10:10. Non-linear modifier only" ) \
2351  X(WL_SHM_FORMAT_Y210 , 8 , "[63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels" ) \
2352  X(WL_SHM_FORMAT_Y212 , 8 , "[63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels" ) \
2353  X(WL_SHM_FORMAT_Y216 , 8 , "[63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels" ) \
2354  X(WL_SHM_FORMAT_Y410 , 4 , "[31:0] A:Cr:Y:Cb 2:10:10:10 little endian" ) \
2355  X(WL_SHM_FORMAT_Y412 , 8 , "[63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian" ) \
2356  X(WL_SHM_FORMAT_Y416 , 8 , "[63:0] A:Cr:Y:Cb 16:16:16:16 little endian" ) \
2357  X(WL_SHM_FORMAT_XVYU2101010 , 4 , "[31:0] X:Cr:Y:Cb 2:10:10:10 little endian" ) \
2358  X(WL_SHM_FORMAT_XVYU12_16161616 , 8 , "[63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian" ) \
2359  X(WL_SHM_FORMAT_XVYU16161616 , 8 , "[63:0] X:Cr:Y:Cb 16:16:16:16 little endian" ) \
2360  X(WL_SHM_FORMAT_Y0L0 , 8 , "[63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian" ) \
2361  X(WL_SHM_FORMAT_X0L0 , 8 , "[63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian" ) \
2362  X(WL_SHM_FORMAT_Y0L2 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2363  X(WL_SHM_FORMAT_X0L2 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2364  X(WL_SHM_FORMAT_YUV420_8BIT , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2365  X(WL_SHM_FORMAT_YUV420_10BIT , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2366  X(WL_SHM_FORMAT_XRGB8888_A8 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2367  X(WL_SHM_FORMAT_XBGR8888_A8 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2368  X(WL_SHM_FORMAT_RGBX8888_A8 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2369  X(WL_SHM_FORMAT_BGRX8888_A8 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2370  X(WL_SHM_FORMAT_RGB888_A8 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2371  X(WL_SHM_FORMAT_BGR888_A8 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2372  X(WL_SHM_FORMAT_RGB565_A8 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2373  X(WL_SHM_FORMAT_BGR565_A8 , 8 , "[63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian" ) \
2374  X(WL_SHM_FORMAT_NV24 , 0 , "[UNKNOWN SIZE] non-subsampled Cr:Cb plane" ) \
2375  X(WL_SHM_FORMAT_NV42 , 0 , "[UNKNOWN SIZE] non-subsampled Cb:Cr plane" ) \
2376  X(WL_SHM_FORMAT_P210 , 0 , "[UNKNOWN SIZE] 2x1 subsampled Cr:Cb plane, 10 bits per channel" ) \
2377  X(WL_SHM_FORMAT_P010 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 10 bits per channel" ) \
2378  X(WL_SHM_FORMAT_P012 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 12 bits per channel" ) \
2379  X(WL_SHM_FORMAT_P016 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 16 bits per channel" ) \
2380 
2381 
2387 #define ZAKERO_YETANI__OUTPUT_SUBPIXEL \
2388  X(WL_OUTPUT_SUBPIXEL_UNKNOWN , "Unkown Subpixel Format" ) \
2389  X(WL_OUTPUT_SUBPIXEL_NONE , "No Subpixels" ) \
2390  X(WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB , "Horizontal RGB" ) \
2391  X(WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR , "Horizontal BGR" ) \
2392  X(WL_OUTPUT_SUBPIXEL_VERTICAL_RGB , "Vertical RGB" ) \
2393  X(WL_OUTPUT_SUBPIXEL_VERTICAL_BGR , "Vertical BGR" ) \
2394 
2395 
2401 #define ZAKERO_YETANI__OUTPUT_TRANSFORM \
2402  X(WL_OUTPUT_TRANSFORM_NORMAL , "No Transform" ) \
2403  X(WL_OUTPUT_TRANSFORM_90 , "90 degrees Counter-Clockwise" ) \
2404  X(WL_OUTPUT_TRANSFORM_180 , "180 degrees Counter-Clockwise" ) \
2405  X(WL_OUTPUT_TRANSFORM_270 , "270 degrees Counter-Clockwise" ) \
2406  X(WL_OUTPUT_TRANSFORM_FLIPPED , "180 degree flip around a vertical axis" ) \
2407  X(WL_OUTPUT_TRANSFORM_FLIPPED_90 , "Flig and rotate 90 degrees counter-clockwise" ) \
2408  X(WL_OUTPUT_TRANSFORM_FLIPPED_180 , "Flig and rotate 180 degrees counter-clockwise" ) \
2409 
2410 
2434 #define ZAKERO_YETANI__ARRAY_FOR_EACH(type_, pos_, array_) \
2435  for(type_ pos_ = (type_)(array_)->data \
2436  ; (const char*)pos_ < ((const char*)(array_)->data + (array_)->size) \
2437  ; (pos_)++ \
2438  )
2439 
2440 // }}}
2441 
2442 namespace zakero
2443 {
2444 // {{{ Anonymous Namespace
2445 
2446 namespace
2447 {
2448  // {{{ Cursor Names (Not used yet)
2449  /*
2450  * \brief Common cursor names
2451  *
2452  * These were found in:
2453  * - gdkcursor-wayland.c
2454  * - /usr/share/icons/whiteglass/cursors
2455  const std::array<const char*, 131> common_cursor_names =
2456  { "X_cursor"
2457  , "alias"
2458  , "all-scroll"
2459  , "arrow"
2460  , "base_arrow_down"
2461  , "base_arrow_up"
2462  , "bd_double_arrow"
2463  , "boat"
2464  , "bottom_left_corner"
2465  , "bottom_right_corner"
2466  , "bottom_side"
2467  , "bottom_tee"
2468  , "cell"
2469  , "center_ptr"
2470  , "circle"
2471  , "closedhand"
2472  , "col-resize"
2473  , "color-picker"
2474  , "context-menu"
2475  , "copy"
2476  , "cross"
2477  , "cross_reverse"
2478  , "crossed_circle"
2479  , "crosshair"
2480  , "default"
2481  , "dnd-copy"
2482  , "dnd-link"
2483  , "dnd-move"
2484  , "dnd-no-drop"
2485  , "dnd-none"
2486  , "dot"
2487  , "dot_box_mask"
2488  , "double_arrow"
2489  , "down-arrow"
2490  , "draft"
2491  , "draft_large"
2492  , "draft_small"
2493  , "draped_box"
2494  , "e-resize"
2495  , "ew-resize"
2496  , "exchange"
2497  , "fd_double_arrow"
2498  , "fleur"
2499  , "forbidden"
2500  , "grab"
2501  , "grabbing"
2502  , "gumby"
2503  , "h_double_arrow"
2504  , "half-busy"
2505  , "hand"
2506  , "hand1"
2507  , "hand2"
2508  , "help"
2509  , "ibeam"
2510  , "left-arrow"
2511  , "left_ptr"
2512  , "left_ptr_help"
2513  , "left_ptr_watch"
2514  , "left_side"
2515  , "left_tee"
2516  , "link"
2517  , "ll_angle"
2518  , "lr_angle"
2519  , "move"
2520  , "n-resize"
2521  , "ne-resize"
2522  , "nesw-resize"
2523  , "no-drop"
2524  , "not-allowed"
2525  , "ns-resize"
2526  , "nw-resize"
2527  , "nwse-resize"
2528  , "openhand"
2529  , "pencil"
2530  , "pirate"
2531  , "plus"
2532  , "pointer"
2533  , "pointing_hand"
2534  , "progress"
2535  , "question_arrow"
2536  , "right-arrow"
2537  , "right_ptr"
2538  , "right_side"
2539  , "right_tee"
2540  , "row-resize"
2541  , "s-resize"
2542  , "sailboat"
2543  , "sb_down_arrow"
2544  , "sb_h_double_arrow"
2545  , "sb_left_arrow"
2546  , "sb_right_arrow"
2547  , "sb_up_arrow"
2548  , "sb_v_double_arrow"
2549  , "se-resize"
2550  , "shuttle"
2551  , "size-bdiag"
2552  , "size-fdiag"
2553  , "size-hor"
2554  , "size-ver"
2555  , "size_all"
2556  , "size_bdiag"
2557  , "size_fdiag"
2558  , "size_hor"
2559  , "size_ver"
2560  , "sizing"
2561  , "split_h"
2562  , "split_v"
2563  , "sw-resize"
2564  , "target"
2565  , "tcross"
2566  , "text"
2567  , "top_left_arrow"
2568  , "top_left_corner"
2569  , "top_right_corner"
2570  , "top_side"
2571  , "top_tee"
2572  , "trek"
2573  , "ul_angle"
2574  , "up-arrow"
2575  , "ur_angle"
2576  , "v_double_arrow"
2577  , "vertical-text"
2578  , "w-resize"
2579  , "wait"
2580  , "watch"
2581  , "wayland-cursor"
2582  , "whats_this"
2583  , "x-cursor"
2584  , "xterm"
2585  , "zoom-in"
2586  , "zoom-out"
2587  };
2588  */
2589  // }}}
2590 
2600  class YetaniErrorCategory_
2601  : public std::error_category
2602  {
2603  public:
2604  constexpr YetaniErrorCategory_() noexcept
2605  {
2606  }
2607 
2608  const char* name() const noexcept override
2609  {
2610  return "zakero.Yetani";
2611  }
2612 
2613  std::string message(int condition
2614  ) const noexcept override
2615  {
2616  switch(condition)
2617  {
2618 #define X(name_, val_, mesg_) \
2619  case val_: return mesg_;
2620  ZAKERO_YETANI__ERROR_DATA
2621 #undef X
2622  }
2623 
2624  return "Unknown error condition";
2625  }
2626  } YetaniErrorCategory;
2627 
2628 
2633  Yetani::Lambda Lambda_DoNothing = []() noexcept {};
2634  Yetani::LambdaKey LambdaKey_DoNothing = [](const Yetani::Key&, const Yetani::KeyModifier&) noexcept {};
2635  Yetani::LambdaAxis LambdaAxis_DoNothing = [](const Yetani::PointerAxis&, const Yetani::KeyModifier&) noexcept {};
2636  Yetani::LambdaButtonMm LambdaButtonMm_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointMm&, const Yetani::KeyModifier&) noexcept {};
2637  Yetani::LambdaButtonPercent LambdaButtonPercent_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointPercent&, const Yetani::KeyModifier&) noexcept {};
2638  Yetani::LambdaButtonPixel LambdaButtonPixel_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointPixel&, const Yetani::KeyModifier&) noexcept {};
2639  Yetani::LambdaPointMm LambdaPointMm_DoNothing = [](const Yetani::PointMm&, const Yetani::KeyModifier&) noexcept {};
2640  Yetani::LambdaPointPercent LambdaPointPercent_DoNothing = [](const Yetani::PointPercent&, const Yetani::KeyModifier&) noexcept {};
2641  Yetani::LambdaPointPixel LambdaPointPixel_DoNothing = [](const Yetani::PointPixel&, const Yetani::KeyModifier&) noexcept {};
2642  Yetani::LambdaBool LambdaBool_DoNothing = [](const bool) noexcept {};
2643  Yetani::LambdaOutputId LambdaOutputId_DoNothing = [](const Yetani::OutputId) noexcept {};
2644  Yetani::LambdaWindowDecorations LambdaWindowDecorations_DoNothing = [](const Yetani::WindowDecorations) noexcept {};
2645  Yetani::LambdaWindowMode LambdaWindowMode_DoNothing = [](const Yetani::WindowMode) noexcept {};
2646  Yetani::LambdaSizeMm LambdaSizeMm_DoNothing = [](const Yetani::SizeMm&) noexcept {};
2647  Yetani::LambdaSizePercent LambdaSizePercent_DoNothing = [](const Yetani::SizePercent&) noexcept {};
2648  Yetani::LambdaSizePixel LambdaSizePixel_DoNothing = [](const Yetani::SizePixel&) noexcept {};
2666  inline size_t sizeInBytes(const Yetani::SizePixel& size
2667  , const wl_shm_format format
2668  ) noexcept
2669  {
2670  return size.width
2671  * size.height
2673  ;
2674  }
2675 
2676 
2690  template<class Type
2691  >
2692  std::error_code validateMinMax(const Type& min
2693  , const Type& max
2694  ) noexcept
2695  {
2696  if((min.width < 0)
2697  || (min.height < 0)
2698  || (max.width < 0)
2699  || (max.height < 0)
2700  )
2701  {
2702  return ZAKERO_YETANI__ERROR(Yetani::Error_Window_Size_Too_Small);
2703  }
2704 
2705  if((min.width > 0)
2706  && (max.width > 0)
2707  && (min.width > max.width)
2708  )
2709  {
2710  return ZAKERO_YETANI__ERROR(Yetani::Error_Minimum_Size_Greater_Than_Maximum_Size);
2711  }
2712 
2713  if((min.height > 0)
2714  && (max.height > 0)
2715  && (min.height > max.height)
2716  )
2717  {
2718  return ZAKERO_YETANI__ERROR(Yetani::Error_Minimum_Size_Greater_Than_Maximum_Size);
2719  }
2720 
2721  return ZAKERO_YETANI__ERROR(Yetani::Error_None);
2722  }
2723 }
2724 
2725 // }}}
2726 // {{{ Documentation
2727 
2884 /* Disabled because Doxygen does not support "enum classes"
2885  *
2886  * \var Yetani::Released
2887  * \brief The key was released
2888  *
2889  * \var Yetani::Pressed
2890  * \brief The key was pressed
2891  *
2892  * \var Yetani::Repeat
2893  * \brief The key is being held down
2894  */
2895 
3010 /* Disabled because Doxygen does not support "enum classes"
3011  *
3012  * \var Yetani::Unknown
3013  * \brief Unknown
3014  *
3015  * \var Yetani::Continuous
3016  * \brief Continuous
3017  *
3018  * \var Yetani::Finger
3019  * \brief Finger
3020  *
3021  * \var Yetani::Wheel
3022  * \brief Wheel
3023  *
3024  * \var Yetani::Wheel_Tilt
3025  * \brief Wheel Tilt
3026  */
3027 
3033 /* Disabled because Doxygen does not support "enum classes"
3034  *
3035  * \var Yetani::Unknown
3036  * \brief Unknown
3037  *
3038  * \var Yetani::Horizontal
3039  * \brief Horizontal
3040  *
3041  * \var Yetani::Vertical
3042  * \brief Vertical
3043  */
3044 
3071 /* Disabled because Doxygen does not support "enum classes"
3072  *
3073  * \var Yetani::Released
3074  * \brief Released
3075  *
3076  * \var Yetani::Pressed
3077  * \brief Pressed
3078  */
3079 
3131 // }}}
3132 // {{{ Static Member Initialization
3133 // {{{ Listener Handler : Wayland
3134 
3135 struct wl_buffer_listener Yetani::buffer_listener =
3136 { .release = &Yetani::handlerBufferRelease
3137 };
3138 
3139 struct wl_callback_listener Yetani::frame_callback_listener =
3140 { .done = &Yetani::handlerSwapBuffers
3141 };
3142 
3143 struct wl_keyboard_listener Yetani::keyboard_listener =
3144 { .keymap = &Yetani::handlerKeyboardKeymap
3145 , .enter = &Yetani::handlerKeyboardEnter
3146 , .leave = &Yetani::handlerKeyboardLeave
3147 , .key = &Yetani::handlerKeyboardKey
3148 , .modifiers = &Yetani::handlerKeyboardModifiers
3149 , .repeat_info = &Yetani::handlerKeyboardRepeatInfo
3150 };
3151 
3152 struct wl_output_listener Yetani::output_listener =
3153 { .geometry = &Yetani::handlerOutputGeometry
3154 , .mode = &Yetani::handlerOutputMode
3155 , .done = &Yetani::handlerOutputDone
3156 , .scale = &Yetani::handlerOutputScale
3157 };
3158 
3159 struct wl_pointer_listener Yetani::pointer_listener =
3160 { .enter = &Yetani::handlerPointerEnter
3161 , .leave = &Yetani::handlerPointerLeave
3162 , .motion = &Yetani::handlerPointerMotion
3163 , .button = &Yetani::handlerPointerButton
3164 , .axis = &Yetani::handlerPointerAxis
3165 , .frame = &Yetani::handlerPointerFrame
3166 , .axis_source = &Yetani::handlerPointerAxisSource
3167 , .axis_stop = &Yetani::handlerPointerAxisStop
3168 , .axis_discrete = &Yetani::handlerPointerAxisDiscrete
3169 };
3170 
3171 struct wl_registry_listener Yetani::registry_listener =
3172 { .global = &Yetani::handlerRegistryGlobal
3173 , .global_remove = &Yetani::handlerRegistryRemove
3174 };
3175 
3176 struct wl_seat_listener Yetani::seat_listener =
3177 { .capabilities = &Yetani::handlerSeatCapabilities
3178 , .name = &Yetani::handlerSeatName
3179 };
3180 
3181 struct wl_shm_listener Yetani::shm_listener =
3182 { .format = &Yetani::handlerShmFormat
3183 };
3184 
3185 struct wl_surface_listener Yetani::surface_listener =
3186 { .enter = &Yetani::handlerSurfaceEnter
3187 , .leave = &Yetani::handlerSurfaceLeave
3188 };
3189 
3190 // }}}
3191 // {{{ Listener Handler : Wayland Unstable
3192 // }}}
3193 // {{{ Listener Handler : XDG
3194 
3195 struct xdg_wm_base_listener Yetani::xdg_wm_base_listener =
3196 { .ping = &Yetani::handlerXdgWmBasePing
3197 };
3198 
3199 struct xdg_surface_listener Yetani::xdg_surface_listener =
3200 { .configure = &Yetani::handlerXdgSurfaceConfigure
3201 };
3202 
3203 struct xdg_toplevel_listener Yetani::xdg_toplevel_listener =
3204 { .configure = &Yetani::handlerXdgToplevelConfigure
3205 , .close = &Yetani::handlerXdgToplevelClose
3206 };
3207 
3208 // }}}
3209 // {{{ Listener Handler : XDG Unstable
3210 
3211 struct zxdg_toplevel_decoration_v1_listener Yetani::xdg_toplevel_decoration_listener =
3212 { .configure = &Yetani::handlerXdgToplevelDecorationConfigure
3213 };
3214 
3215 // }}}
3216 // }}}
3217 // {{{ Constructor / Destructor
3218 
3224 Yetani::Yetani() noexcept
3225  : cursor_map()
3226  , cursor_surface_map()
3227  , cursor_memory_pool(
3228  std::string("Zakero.Yetani.")
3229  + std::to_string(ZAKERO_STEADY_TIME_NOW(nanoseconds))
3230  )
3231  , cursor_mutex()
3232  , cursor_shm_pool(nullptr)
3233  , cursor_pointer(nullptr)
3234  , event_loop()
3235  , event_loop_is_running(false)
3236  , compositor(nullptr)
3237  , display(nullptr)
3238  , registry(nullptr)
3239  , shm(nullptr)
3240  , shm_format_vector()
3241  , seat_map()
3242  , id_to_seat()
3243  , seat(nullptr)
3244  , keyboard()
3245  , pointer()
3246  , output_data()
3247  , on_output_add(LambdaOutputId_DoNothing)
3248  , on_output_change(LambdaOutputId_DoNothing)
3249  , on_output_remove(LambdaOutputId_DoNothing)
3250  , output_changes_map()
3251  , output_state_map()
3252  , output_notify_surface_vector()
3253  , buffer()
3254  , surface_event_map()
3255  , surface_extent_map()
3256  , surface_extent_mutex()
3257  , surface_frame_map()
3258  , surface_size_map()
3259  , surface_resize_mutex_map()
3260  , window_vector()
3261  , window_vector_mutex()
3262  , xdg_state_change_map()
3263  , xdg_state_change_mutex()
3264  , xdg_wm_base(nullptr)
3265  , xdg_surface_map()
3266  , xdg_toplevel_map()
3267  , xdg_decoration_map()
3268  , decoration_manager(nullptr)
3269 {
3270 }
3271 
3272 
3283 {
3284  if(event_loop_is_running || event_loop.joinable())
3285  {
3286  event_loop.request_stop();
3287  event_loop.join();
3288  }
3289 
3290  disconnect();
3291 }
3292 
3293 // }}}
3294 // {{{ Connection
3295 
3319 {
3320  std::error_code error;
3321 
3322  return Yetani::connect("", error);
3323 }
3324 
3325 
3350 Yetani* Yetani::connect(const std::string& display
3351  ) noexcept
3352 {
3353  std::error_code error;
3354 
3355  return Yetani::connect(display, error);
3356 }
3357 
3358 
3386 Yetani* Yetani::connect(std::error_code& error
3387  ) noexcept
3388 {
3389  return Yetani::connect("", error);
3390 }
3391 
3421 Yetani* Yetani::connect(const std::string& display
3422  , std::error_code& error
3423  ) noexcept
3424 {
3425  Yetani* yetani = new Yetani();
3426 
3427  const char* display_name = nullptr;
3428 
3429  if(display.empty() == false)
3430  {
3431  display_name = display.c_str();
3432  }
3433 
3434  // --- Get the Display --- //
3435  yetani->display = wl_display_connect(display_name);
3436  if(yetani->display == nullptr)
3437  {
3438  delete yetani;
3439 
3440  const char* session = getenv("XDG_SESSION_TYPE");
3441 
3442  if(session != nullptr
3443  && strcasecmp(session, "wayland") != 0
3444  )
3445  {
3446  error = ZAKERO_YETANI__ERROR(Error_Wayland_Not_Available);
3447  }
3448  else if(display.empty())
3449  {
3450  error = ZAKERO_YETANI__ERROR(Error_Connection_Failed);
3451  }
3452  else
3453  {
3454  error = ZAKERO_YETANI__ERROR(Error_Invalid_Display_Name);
3455  }
3456 
3457  return nullptr;
3458  }
3459 
3460  // --- Get the Registry --- //
3461  yetani->registry = wl_display_get_registry(yetani->display);
3462  if(yetani->registry == nullptr)
3463  {
3464  delete yetani;
3465 
3466  error = ZAKERO_YETANI__ERROR(Error_Registry_Not_Available);
3467 
3468  return nullptr;
3469  }
3470 
3471  wl_registry_add_listener(yetani->registry, &registry_listener, yetani);
3472 
3473  // --- Wait for all Global Objects to be registered --- //
3474  wl_display_dispatch(yetani->display);
3475  wl_display_roundtrip(yetani->display);
3476 
3477  // --- Validate required Global Objects --- //
3478  if(yetani->compositor == nullptr)
3479  {
3480  delete yetani;
3481 
3482  error = ZAKERO_YETANI__ERROR(Error_Compositor_Was_Not_Found);
3483 
3484  return nullptr;
3485  }
3486 
3487  if(yetani->shm == nullptr)
3488  {
3489  delete yetani;
3490 
3491  error = ZAKERO_YETANI__ERROR(Error_Shm_Was_Not_Found);
3492 
3493  return nullptr;
3494  }
3495 
3496  if(yetani->xdg_wm_base == nullptr)
3497  {
3498  delete yetani;
3499 
3500  error = ZAKERO_YETANI__ERROR(Error_Xdg_WM_Base_Was_Not_Found);
3501 
3502  return nullptr;
3503  }
3504 
3505  yetani->cursorSetup();
3506 
3507  yetani->eventLoopStart();
3508 
3509  error = ZAKERO_YETANI__ERROR(Error_None);
3510 
3511  return yetani;
3512 }
3513 
3514 
3524 void Yetani::disconnect() noexcept
3525 {
3526  cursorTeardown();
3527 
3528  if(decoration_manager != nullptr)
3529  {
3530  zxdg_decoration_manager_v1_destroy(decoration_manager);
3531  decoration_manager = nullptr;
3532  }
3533 
3534  if(xdg_wm_base != nullptr)
3535  {
3536  xdg_wm_base_destroy(xdg_wm_base);
3537  xdg_wm_base = nullptr;
3538  }
3539 
3540  if(shm != nullptr)
3541  {
3542  wl_shm_destroy(shm);
3543  shm = nullptr;
3544  }
3545 
3546  // Seat
3547  id_to_seat.clear();
3548 
3549  while(seat_map.empty() == false)
3550  {
3551  auto iter = std::begin(seat_map);
3552 
3553  struct wl_seat* wl_seat = iter->first;
3554 
3555  seatDestroy(wl_seat);
3556  }
3557 
3558  // Wayland Output Devices
3559  {
3560  std::lock_guard<std::mutex> lock(output_data.mutex);
3561 
3562  for(auto& iter : output_data.output_map)
3563  {
3564  struct wl_output* wayland_output = iter.first;
3565 
3566  wl_output_destroy(wayland_output);
3567  }
3568 
3569  output_changes_map.clear();
3570  output_state_map.clear();
3571  output_data.output_map.clear();
3572  output_data.wloutput_to_outputid.clear();
3573  output_data.outputid_to_wloutput.clear();
3574  }
3575 
3576  if(registry != nullptr)
3577  {
3578  wl_registry_destroy(registry);
3579  registry = nullptr;
3580  }
3581 
3582  if(compositor != nullptr)
3583  {
3584  wl_compositor_destroy(compositor);
3585  compositor = nullptr;
3586  }
3587 
3588  if(display != nullptr)
3589  {
3590  wl_display_disconnect(display);
3591  display = nullptr;
3592  }
3593 
3594  return;
3595 }
3596 
3597 // }}}
3598 // {{{ Cursor
3599 
3732 void Yetani::cursorAnimate() noexcept
3733 {
3734  int64_t time_now = ZAKERO_STEADY_TIME_NOW(milliseconds);
3735 
3736  std::lock_guard<std::mutex> lock(cursor_mutex);
3737 
3738  for(auto& iter : cursor_map)
3739  {
3740  Yetani::Cursor& cursor = iter.second;
3741 
3742  if(cursor.next_frame_time <= time_now)
3743  {
3744  const int64_t time_over = time_now - cursor.next_frame_time;
3745  cursor.next_frame_time = time_now + cursor.time_per_frame - time_over;
3746 
3747  cursor.buffer_index = (cursor.buffer_index + 1) % cursor.buffer_vector.size();
3748 
3749  wl_surface_attach(cursor.wl_surface, cursor.buffer_vector[cursor.buffer_index], 0, 0);
3750  wl_surface_damage(cursor.wl_surface
3751  , 0, 0
3752  , cursor.width, cursor.height
3753  );
3754 
3755  wl_surface_commit(cursor.wl_surface);
3756  }
3757  }
3758 }
3759 
3760 
3801 std::error_code Yetani::cursorCreate(const std::string& name
3802  , const Yetani::CursorConfig& config
3803  ) noexcept
3804 {
3805  if(name.empty())
3806  {
3807  return ZAKERO_YETANI__ERROR(Error_Cursor_Name_Is_Invalid);
3808  }
3809 
3810  if(cursor_map.contains(name) == true)
3811  {
3812  return ZAKERO_YETANI__ERROR(Error_Cursor_Already_Exists);
3813  }
3814 
3815  if(config.size.width <= 0 || config.size.height <= 0)
3816  {
3817  return ZAKERO_YETANI__ERROR(Error_Cursor_Size_Too_Small);
3818  }
3819 
3820  if(config.image_data.empty())
3821  {
3822  return ZAKERO_YETANI__ERROR(Error_Cursor_Image_Data_Is_Empty);
3823  }
3824  else if(config.image_data.size() > 1)
3825  {
3826  if(config.time_per_frame.count() <= 0)
3827  {
3828  return ZAKERO_YETANI__ERROR(Error_Cursor_Frame_Time_Too_Small);
3829  }
3830 
3831  if(config.time_per_frame.count() > Size_Max)
3832  {
3833  return ZAKERO_YETANI__ERROR(Error_Cursor_Frame_Time_Too_Large);
3834  }
3835  }
3836 
3837  std::error_code error = cursorCreateCursor(name, config);
3838 
3839  return error;
3840 }
3841 
3842 
3853 std::error_code Yetani::cursorCreateCursor(const std::string& cursor_name
3854  , const Yetani::CursorConfig& cursor_config
3855  ) noexcept
3856 {
3857  const uint8_t bytes_per_pixel = shmFormatBytesPerPixel(cursor_config.format);
3858  const size_t frame_count = cursor_config.image_data.size();
3859 
3860  Yetani::Cursor cursor =
3861  { .wl_surface = wl_compositor_create_surface(compositor)
3862  , .buffer_vector = { frame_count, nullptr }
3863  , .format = cursor_config.format
3864  , .next_frame_time = ZAKERO_STEADY_TIME_NOW(milliseconds)
3865  , .buffer_index = 0
3866  , .time_per_frame = uint32_t(cursor_config.time_per_frame.count())
3867  , .width = cursor_config.size.width
3868  , .height = cursor_config.size.height
3869  , .hotspot_x = cursor_config.hotspot_x
3870  , .hotspot_y = cursor_config.hotspot_y
3871  };
3872 
3873  if(cursor.time_per_frame == 0)
3874  {
3875  cursor.time_per_frame = Size_Max;
3876  }
3877 
3878  const int stride = cursor.width * bytes_per_pixel;
3879  const size_t image_size = stride * cursor.height;
3880 
3881  for(size_t i = 0; i < frame_count; i++)
3882  {
3883  std::error_code error;
3884 
3885  off_t offset = cursor_memory_pool.alloc(image_size, error);
3886  if(error)
3887  {
3888  while(i > 0)
3889  {
3890  i--;
3891 
3892  struct wl_buffer* buffer = cursor.buffer_vector[i];
3893  cursor.buffer_vector[i] = nullptr;
3894 
3895  off_t offset = (off_t)wl_buffer_get_user_data(buffer);
3896  wl_buffer_destroy(buffer);
3897 
3898  cursor_memory_pool.free(offset);
3899  }
3900 
3901  return error;
3902  }
3903 
3904  uint32_t* p = (uint32_t*)cursor_memory_pool.addressOf(offset);
3905  memcpy(p, (uint8_t*)cursor_config.image_data[i], image_size);
3906 
3907  cursor.buffer_vector[i] = wl_shm_pool_create_buffer(cursor_shm_pool
3908  , offset
3909  , cursor.width
3910  , cursor.height
3911  , stride
3912  , cursor.format
3913  );
3914 
3915  wl_buffer_set_user_data(cursor.buffer_vector[i], (void*)offset);
3916  }
3917 
3918  wl_surface_attach(cursor.wl_surface, cursor.buffer_vector[0], 0, 0);
3919  wl_surface_commit(cursor.wl_surface);
3920 
3921  std::lock_guard<std::mutex> lock(cursor_mutex);
3922 
3923  cursor_map[cursor_name] = cursor;
3924 
3925  return ZAKERO_YETANI__ERROR(Error_None);
3926 }
3927 
3928 
3939 std::error_code Yetani::cursorDestroy(const std::string& name
3940  ) noexcept
3941 {
3942  Yetani::Cursor cursor;
3943 
3944  {
3945  std::lock_guard<std::mutex> lock(cursor_mutex);
3946 
3947  if(cursor_map.contains(name) == false)
3948  {
3949  return ZAKERO_YETANI__ERROR(Error_Cursor_Does_Not_Exist);
3950  }
3951 
3952  cursor = cursor_map[name];
3953 
3954  cursor_map.erase(name);
3955  }
3956 
3957  auto iter = std::begin(cursor_surface_map);
3958  auto iter_end = std::end(cursor_surface_map);
3959  while(iter != iter_end)
3960  {
3961  if(cursor.wl_surface == iter->second.wl_surface)
3962  {
3963  iter = cursor_surface_map.erase(iter);
3964  }
3965  else
3966  {
3967  iter++;
3968  }
3969  }
3970 
3971  if(cursor.wl_surface)
3972  {
3973  wl_surface_destroy(cursor.wl_surface);
3974  cursor.wl_surface = nullptr;
3975  }
3976 
3977  for(wl_buffer* buffer : cursor.buffer_vector)
3978  {
3979  off_t offset = (off_t)wl_buffer_get_user_data(buffer);
3980  wl_buffer_destroy(buffer);
3981 
3982  cursor_memory_pool.free(offset);
3983  }
3984 
3985  return ZAKERO_YETANI__ERROR(Error_None);
3986 }
3987 
3988 
3997 void Yetani::cursorEnter(wl_pointer* wl_pointer
3998  , uint32_t serial
3999  , struct wl_surface* wl_surface
4000  ) noexcept
4001 {
4002  std::lock_guard<std::mutex> lock(cursor_mutex);
4003 
4004  cursor_pointer = wl_pointer;
4005 
4006  if(cursor_surface_map.contains(wl_surface) == false)
4007  {
4008  return;
4009  }
4010 
4011  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4012 
4013  cursor_surface.wl_pointer = wl_pointer;
4014  cursor_surface.serial = serial;
4015 
4016  if(cursor_surface.is_visible)
4017  {
4018  wl_pointer_set_cursor(cursor_surface.wl_pointer
4019  , cursor_surface.serial
4020  , cursor_surface.wl_surface
4021  , cursor_surface.hotspot_x
4022  , cursor_surface.hotspot_y
4023  );
4024  }
4025  else
4026  {
4027  wl_pointer_set_cursor(cursor_surface.wl_pointer
4028  , cursor_surface.serial
4029  , nullptr
4030  , 0
4031  , 0
4032  );
4033  }
4034 }
4035 
4036 
4046 void Yetani::cursorLeave(struct wl_surface* wl_surface
4047  ) noexcept
4048 {
4049  std::lock_guard<std::mutex> lock(cursor_mutex);
4050 
4051  cursor_pointer = nullptr;
4052 
4053  if(cursor_surface_map.contains(wl_surface) == false)
4054  {
4055  return;
4056  }
4057 
4058  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4059 
4060  cursor_surface.wl_pointer = nullptr;
4061  cursor_surface.serial = 0;
4062 }
4063 
4064 
4072 void Yetani::cursorHide(struct wl_surface* wl_surface
4073  ) noexcept
4074 {
4075  std::lock_guard<std::mutex> lock(cursor_mutex);
4076 
4077  if(cursor_surface_map.contains(wl_surface) == false)
4078  {
4079  return;
4080  }
4081 
4082  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4083 
4084  cursor_surface.is_visible = false;
4085 
4086  if(cursor_surface.wl_pointer != nullptr)
4087  {
4088  wl_pointer_set_cursor(cursor_surface.wl_pointer
4089  , cursor_surface.serial
4090  , nullptr
4091  , 0
4092  , 0
4093  );
4094  }
4095 }
4096 
4097 
4105 void Yetani::cursorShow(struct wl_surface* wl_surface
4106  ) noexcept
4107 {
4108  std::lock_guard<std::mutex> lock(cursor_mutex);
4109 
4110  if(cursor_surface_map.contains(wl_surface) == false)
4111  {
4112  return;
4113  }
4114 
4115  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4116 
4117  cursor_surface.is_visible = true;
4118 
4119  if(cursor_surface.wl_pointer != nullptr)
4120  {
4121  wl_pointer_set_cursor(cursor_surface.wl_pointer
4122  , cursor_surface.serial
4123  , cursor_surface.wl_surface
4124  , cursor_surface.hotspot_x
4125  , cursor_surface.hotspot_y
4126  );
4127  }
4128 }
4129 
4130 
4141 bool Yetani::cursorIsHidden(struct wl_surface* wl_surface
4142  ) const noexcept
4143 {
4144  std::lock_guard<std::mutex> lock(cursor_mutex);
4145 
4146  if(cursor_surface_map.contains(wl_surface) == false)
4147  {
4148  return true;
4149  }
4150 
4151  const Yetani::CursorSurface& cursor_surface = cursor_surface_map.at(wl_surface);
4152 
4153  return !(cursor_surface.is_visible);
4154 }
4155 
4156 
4164 void Yetani::cursorSetup() noexcept
4165 {
4166  cursor_map.clear();
4167 
4168  uint64_t bytes = zakero::convert((uint64_t)4, zakero::Storage::Kilobyte, zakero::Storage::Byte);
4169  cursor_memory_pool.init(bytes, true, zakero::MemoryPool::Alignment::Bits_32);
4170 
4171  cursor_memory_pool.sizeOnChange([&](size_t new_size)
4172  {
4173  wl_shm_pool_resize(cursor_shm_pool, new_size);
4174  });
4175 
4176  cursor_shm_pool = wl_shm_create_pool(shm, cursor_memory_pool.fd(), cursor_memory_pool.size());
4177 }
4178 
4179 
4187 void Yetani::cursorTeardown() noexcept
4188 {
4189  while(cursor_map.empty() == false)
4190  {
4191  const auto& iter = cursor_map.begin();
4192 
4193  const std::string& name = iter->first;
4194 
4195  cursorDestroy(name);
4196  }
4197 
4198  if(cursor_shm_pool != nullptr)
4199  {
4200  wl_shm_pool_destroy(cursor_shm_pool);
4201  }
4202 }
4203 
4204 
4216 std::error_code Yetani::cursorAttach(const std::string& cursor_name
4217  , struct wl_surface* wl_surface
4218  ) noexcept
4219 {
4220  std::lock_guard<std::mutex> lock(cursor_mutex);
4221 
4222  if(cursor_map.contains(cursor_name) == false)
4223  {
4224  return ZAKERO_YETANI__ERROR(Error_Cursor_Does_Not_Exist);
4225  }
4226 
4227  if(cursor_surface_map.contains(wl_surface) == false)
4228  {
4229  cursor_surface_map[wl_surface] =
4230  { .wl_pointer = cursor_pointer
4231  , .wl_surface = nullptr
4232  , .serial = 0
4233  , .hotspot_x = 0
4234  , .hotspot_y = 0
4235  , .is_visible = true
4236  };
4237  }
4238 
4239  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4240  Yetani::Cursor& cursor = cursor_map[cursor_name];
4241 
4242  cursor_surface.wl_surface = cursor.wl_surface;
4243  cursor_surface.hotspot_x = cursor.hotspot_x;
4244  cursor_surface.hotspot_y = cursor.hotspot_y;
4245 
4246  if(cursor_surface.wl_pointer != nullptr)
4247  {
4248  if(cursor_surface.is_visible)
4249  {
4250  wl_pointer_set_cursor(cursor_surface.wl_pointer
4251  , cursor_surface.serial
4252  , cursor_surface.wl_surface
4253  , cursor_surface.hotspot_x
4254  , cursor_surface.hotspot_y
4255  );
4256  }
4257  else
4258  {
4259  wl_pointer_set_cursor(cursor_surface.wl_pointer
4260  , cursor_surface.serial
4261  , nullptr
4262  , 0
4263  , 0
4264  );
4265  }
4266  }
4267 
4268  return ZAKERO_YETANI__ERROR(Error_None);
4269 }
4270 
4271 
4283 std::error_code Yetani::cursorDetach(struct wl_surface* wl_surface
4284  ) noexcept
4285 {
4286  std::lock_guard<std::mutex> lock(cursor_mutex);
4287 
4288  if(cursor_surface_map.contains(wl_surface) == false)
4289  {
4290  return ZAKERO_YETANI__ERROR(Error_Cursor_Not_Attached);
4291  }
4292 
4293  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4294 
4295  if(cursor_surface.wl_pointer != nullptr)
4296  {
4297  wl_pointer_set_cursor(cursor_surface.wl_pointer
4298  , cursor_surface.serial
4299  , nullptr
4300  , 0
4301  , 0
4302  );
4303  }
4304 
4305  cursor_surface_map.erase(wl_surface);
4306 
4307  return ZAKERO_YETANI__ERROR(Error_None);
4308 }
4309 
4310 // }}}
4311 // {{{ Event Loop
4312 
4313 //#define ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4314 
4323 void Yetani::eventLoopStart() noexcept
4324 {
4325  event_loop = std::jthread(&Yetani::eventLoop, this);
4326 
4327  while(event_loop_is_running.load() == false)
4328  {
4329  // Wait for the thread to start
4330  std::this_thread::sleep_for(std::chrono::nanoseconds(42));
4331  }
4332 
4333  #ifdef ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4334  int policy = SCHED_FIFO;
4335  int priority_min = sched_get_priority_min(policy);
4336  int priority_max = sched_get_priority_max(policy);
4337 
4338  sched_param sched =
4339  { .sched_priority = (priority_min + priority_max) / 2
4340  };
4341 
4342  pthread_setschedparam(event_loop.native_handle(), policy, &sched);
4343  #endif
4344 }
4345 
4346 
4374 void Yetani::eventLoop(std::stop_token thread_token
4375  , Yetani* yetani
4376  ) noexcept
4377 {
4378  struct pollfd fd_status =
4379  { .fd = wl_display_get_fd(yetani->display)
4380  , .events = POLLIN | POLLOUT
4381  , .revents = 0
4382  };
4383 
4384  yetani->event_loop_is_running.store(true);
4385 
4386  // Handle events and render window contents
4387  while(thread_token.stop_requested() == false)
4388  {
4389  poll(&fd_status, 1, 1);
4390 
4391  if(fd_status.revents & POLLIN)
4392  {
4393  wl_display_dispatch(yetani->display);
4394  }
4395 
4396  yetani->cursorAnimate();
4397 
4398  keyboardRepeat(yetani->keyboard);
4399 
4400  if(fd_status.revents & POLLOUT)
4401  {
4402  wl_display_flush(yetani->display);
4403  }
4404 
4405  #ifdef ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4406  std::this_thread::yield();
4407  #endif
4408  }
4409 
4410  yetani->event_loop_is_running.store(false);
4411 }
4412 
4413 // }}}
4414 // {{{ Shared Memory
4415 
4426 const Yetani::VectorShmFormat& Yetani::shmFormatAvailable() const noexcept
4427 {
4428  return shm_format_vector;
4429 }
4430 
4431 
4443 uint8_t Yetani::shmFormatBytesPerPixel(const wl_shm_format shm_format
4444  ) noexcept
4445 {
4446  switch(shm_format)
4447  {
4448 #define X(value_, bytes_, desc_) \
4449  case value_: return bytes_;
4450  ZAKERO_YETANI__SHM_FORMAT
4451 #undef X
4452  default: return 0;
4453  }
4454 }
4455 
4456 
4468 std::string Yetani::shmFormatDescription(const wl_shm_format shm_format
4469  ) noexcept
4470 {
4471  switch(shm_format)
4472  {
4473 #define X(value_, bytes_, desc_) \
4474  case value_: return desc_;
4475  ZAKERO_YETANI__SHM_FORMAT
4476 #undef X
4477  default: return "";
4478  }
4479 }
4480 
4481 
4491 std::string Yetani::shmFormatName(const wl_shm_format shm_format
4492  ) noexcept
4493 {
4494  switch(shm_format)
4495  {
4496 #define X(value_, bytes_, desc_) \
4497  case value_: return #value_;
4498  ZAKERO_YETANI__SHM_FORMAT
4499 #undef X
4500  default: return "";
4501  }
4502 }
4503 
4504 // }}}
4505 // {{{ Utility
4506 
4507 
4508 // }}}
4509 // {{{ Wayland : Buffer
4510 
4551 struct wl_buffer* Yetani::bufferCreate(Yetani::SurfaceSize& surface_size
4552  , Yetani::Window::Memory* window_memory
4553  , Yetani::Buffer* buffer
4554  ) noexcept
4555 {
4556  off_t offset = window_memory->memory_pool.alloc(surface_size.in_bytes);
4557 
4558  struct wl_buffer* wl_buffer = wl_shm_pool_create_buffer(window_memory->wl_shm_pool
4559  , offset
4560  , surface_size.width
4561  , surface_size.height
4562  , surface_size.stride
4563  , surface_size.pixel_format
4564  );
4565 
4566  wl_buffer_set_user_data(wl_buffer, buffer);
4567 
4568  buffer->mutex.lock();
4569  {
4570  buffer->map[wl_buffer] =
4571  { .memory_pool = &window_memory->memory_pool
4572  , .offset = offset
4573  };
4574  }
4575  buffer->mutex.unlock();
4576 
4577  return wl_buffer;
4578 }
4579 
4580 
4590 void Yetani::bufferDestroy(struct wl_buffer*& wl_buffer
4591  ) noexcept
4592 {
4593  Yetani::Buffer* buffer = (Yetani::Buffer*)wl_buffer_get_user_data(wl_buffer);
4594 
4595  wl_buffer_destroy(wl_buffer);
4596 
4597  buffer->mutex.lock();
4598  {
4599  BufferData& buffer_data = buffer->map[wl_buffer];
4600 
4601  buffer_data.memory_pool->free(buffer_data.offset);
4602 
4603  buffer->map.erase(wl_buffer);
4604  }
4605  buffer->mutex.unlock();
4606 
4607  wl_buffer = nullptr;
4608 }
4609 
4610 // }}}
4611 // {{{ Wayland : Output
4612 
4708 Yetani::Output Yetani::output(const Yetani::OutputId output_id
4709  ) const noexcept
4710 {
4711  std::lock_guard<std::mutex> lock(output_data.mutex);
4712 
4713  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4714  {
4715  ZAKERO_YETANI__DEBUG
4716  << "Invalid output_id: "
4717  << std::to_string(output_id)
4718  ;
4719 
4720  return {};
4721  }
4722 
4723  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4724 
4725  return output_data.output_map.at(wl_output);
4726 }
4727 
4728 
4740 Yetani::VectorOutputId Yetani::outputVector() const noexcept
4741 {
4742  Yetani::VectorOutputId vector;
4743 
4744  std::lock_guard<std::mutex> lock(output_data.mutex);
4745 
4746  for(const auto& iter : output_data.outputid_to_wloutput)
4747  {
4748  vector.push_back(iter.first);
4749  }
4750 
4751  return vector;
4752 }
4753 
4754 
4766 std::string Yetani::outputSubpixelName(int32_t subpixel_format
4767  ) noexcept
4768 {
4769  switch(subpixel_format)
4770  {
4771 #define X(value_, name_) \
4772  case value_: return name_;
4773  ZAKERO_YETANI__OUTPUT_SUBPIXEL
4774 #undef X
4775  default: return "";
4776  }
4777 }
4778 
4779 
4791 std::string Yetani::outputTransformName(int32_t transform
4792  ) noexcept
4793 {
4794  switch(transform)
4795  {
4796 #define X(value_, name_) \
4797  case value_: return name_;
4798  ZAKERO_YETANI__OUTPUT_TRANSFORM
4799 #undef X
4800  default: return "";
4801  }
4802 }
4803 
4804 
4815 Yetani::PointMm Yetani::outputConvertToMm(const Yetani::OutputId output_id
4816  , const Yetani::PointPixel& point
4817  ) const noexcept
4818 {
4819  std::lock_guard<std::mutex> lock(output_data.mutex);
4820 
4821  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4822  {
4823  return { point.time, 0, 0 };
4824  }
4825 
4826  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4827  const Yetani::Output& output = output_data.output_map.at(wl_output);
4828 
4829  auto p = convertPixelToMm(output, point.x, point.y);
4830 
4831  return { point.time, p.first, p.second };
4832 }
4833 
4834 
4845 Yetani::PointPercent Yetani::outputConvertToPercent(const Yetani::OutputId output_id
4846  , const Yetani::PointPixel& point
4847  ) const noexcept
4848 {
4849  std::lock_guard<std::mutex> lock(output_data.mutex);
4850 
4851  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4852  {
4853  return { point.time, 0, 0 };
4854  }
4855 
4856  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4857  const Yetani::Output& output = output_data.output_map.at(wl_output);
4858 
4859  auto p = convertPixelToPercent(output, point.x, point.y);
4860 
4861  return { point.time, p.first, p.second };
4862 }
4863 
4864 
4875 Yetani::PointPixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4876  , const Yetani::PointMm& point
4877  ) const noexcept
4878 {
4879  std::lock_guard<std::mutex> lock(output_data.mutex);
4880 
4881  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4882  {
4883  return { point.time, 0, 0 };
4884  }
4885 
4886  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4887  const Yetani::Output& output = output_data.output_map.at(wl_output);
4888 
4889  auto p = convertMmToPixel(output, point.x, point.y);
4890 
4891  return { point.time, p.first, p.second };
4892 }
4893 
4894 
4905 Yetani::PointPixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4906  , const Yetani::PointPercent& point
4907  ) const noexcept
4908 {
4909  std::lock_guard<std::mutex> lock(output_data.mutex);
4910 
4911  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4912  {
4913  return { point.time, 0, 0 };
4914  }
4915 
4916  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4917  const Yetani::Output& output = output_data.output_map.at(wl_output);
4918 
4919  auto p = convertPercentToPixel(output, point.x, point.y);
4920 
4921  return { point.time, p.first, p.second };
4922 }
4923 
4924 
4935 Yetani::SizeMm Yetani::outputConvertToMm(const Yetani::OutputId output_id
4936  , const Yetani::SizePixel& size
4937  ) const noexcept
4938 {
4939  std::lock_guard<std::mutex> lock(output_data.mutex);
4940 
4941  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4942  {
4943  return { 0, 0 };
4944  }
4945 
4946  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4947  const Yetani::Output& output = output_data.output_map.at(wl_output);
4948 
4949  auto p = convertPixelToMm(output, size.width, size.height);
4950 
4951  return { p.first, p.second };
4952 }
4953 
4954 
4965 Yetani::SizePercent Yetani::outputConvertToPercent(const Yetani::OutputId output_id
4966  , const Yetani::SizePixel& size
4967  ) const noexcept
4968 {
4969  std::lock_guard<std::mutex> lock(output_data.mutex);
4970 
4971  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4972  {
4973  return { 0, 0 };
4974  }
4975 
4976  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4977  const Yetani::Output& output = output_data.output_map.at(wl_output);
4978 
4979  auto p = convertPixelToPercent(output, size.width, size.height);
4980 
4981  return { p.first, p.second };
4982 }
4983 
4984 
4994 Yetani::SizePixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4995  , const Yetani::SizeMm& size
4996  ) const noexcept
4997 {
4998  std::lock_guard<std::mutex> lock(output_data.mutex);
4999 
5000  if(output_data.outputid_to_wloutput.contains(output_id) == false)
5001  {
5002  return { 0, 0 };
5003  }
5004 
5005  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
5006  const Yetani::Output& output = output_data.output_map.at(wl_output);
5007 
5008  auto p = convertMmToPixel(output, size.width, size.height);
5009 
5010  return { p.first, p.second };
5011 }
5012 
5013 
5023 Yetani::SizePixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
5024  , const Yetani::SizePercent& size
5025  ) const noexcept
5026 {
5027  std::lock_guard<std::mutex> lock(output_data.mutex);
5028 
5029  if(output_data.outputid_to_wloutput.contains(output_id) == false)
5030  {
5031  return { 0, 0 };
5032  }
5033 
5034  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
5035  const Yetani::Output& output = output_data.output_map.at(wl_output);
5036 
5037  auto p = convertPercentToPixel(output, size.width, size.height);
5038 
5039  return { p.first, p.second };
5040 }
5041 
5042 
5052 void Yetani::outputOnAdd(LambdaOutputId lambda
5053  ) noexcept
5054 {
5055  if(lambda == nullptr)
5056  {
5057  on_output_add = LambdaOutputId_DoNothing;
5058  }
5059  else
5060  {
5061  on_output_add = lambda;
5062  }
5063 }
5064 
5065 
5075 void Yetani::outputOnChange(LambdaOutputId lambda
5076  ) noexcept
5077 {
5078  if(lambda == nullptr)
5079  {
5080  on_output_change = LambdaOutputId_DoNothing;
5081  }
5082  else
5083  {
5084  on_output_change = lambda;
5085  }
5086 }
5087 
5088 
5098 void Yetani::outputOnRemove(LambdaOutputId lambda
5099  ) noexcept
5100 {
5101  if(lambda == nullptr)
5102  {
5103  on_output_remove = LambdaOutputId_DoNothing;
5104  }
5105  else
5106  {
5107  on_output_remove = lambda;
5108  }
5109 }
5110 
5111 
5120 void Yetani::convertPixel(struct wl_surface* wl_surface
5121  , const int32_t pixel_xw
5122  , const int32_t pixel_yh
5123  , float& mm_xw
5124  , float& mm_yh
5125  , float& pc_xw
5126  , float& pc_yh
5127  ) const noexcept
5128 {
5129  std::lock_guard<std::mutex> lock(output_data.mutex);
5130 
5131  const Yetani::VectorWlOutput& vector = output_data.surface_output_map.at(wl_surface);
5132  struct wl_output* wl_output = vector.front();
5133  const Yetani::Output& output = output_data.output_map.at(wl_output);
5134 
5135  auto mm = convertPixelToMm(output, pixel_xw, pixel_yh);
5136  mm_xw = mm.first;
5137  mm_yh = mm.second;
5138 
5139  auto pc = convertPixelToPercent(output, pixel_xw, pixel_yh);
5140  pc_xw = pc.first;
5141  pc_yh = pc.second;
5142 }
5143 
5144 
5156 std::pair<float, float> Yetani::convertPixelToMm(const Yetani::Output& output
5157  , int32_t xw
5158  , int32_t yh
5159  ) const noexcept
5160 {
5161  const float ratio_h = output.pixels_per_mm_horizontal;
5162  const float ratio_v = output.pixels_per_mm_vertical;
5163 
5164  return
5165  { xw / ratio_h
5166  , yh / ratio_v
5167  };
5168 }
5169 
5170 
5182 std::pair<float, float> Yetani::convertPixelToPercent(const Yetani::Output& output
5183  , int32_t xw
5184  , int32_t yh
5185  ) const noexcept
5186 {
5187  return
5188  { float(xw) / output.width
5189  , float(yh) / output.height
5190  };
5191 }
5192 
5193 
5205 std::pair<int32_t, int32_t> Yetani::convertMmToPixel(const Yetani::Output& output
5206  , float xw
5207  , float yh
5208  ) const noexcept
5209 {
5210  const float ratio_h = output.pixels_per_mm_horizontal;
5211  const float ratio_v = output.pixels_per_mm_vertical;
5212 
5213  return
5214  { int32_t(xw * ratio_h)
5215  , int32_t(yh * ratio_v)
5216  };
5217 }
5218 
5219 
5231 std::pair<int32_t, int32_t> Yetani::convertPercentToPixel(const Yetani::Output& output
5232  , float xw
5233  , float yh
5234  ) const noexcept
5235 {
5236  return
5237  { int32_t(xw * output.width)
5238  , int32_t(yh * output.height)
5239  };
5240 }
5241 
5242 
5254 void Yetani::outputNotifySurface(Yetani* yetani
5255  , struct wl_output* wl_output
5256  , struct wl_surface* wl_surface
5257  ) noexcept
5258 {
5259  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
5260  if(surface_extent.preferred_unit == Yetani::SizeUnit::Pixel)
5261  {
5262  return;
5263  }
5264 
5265  Yetani::OutputData& output_data = yetani->output_data;
5266 
5267  std::lock_guard<std::mutex> lock(output_data.mutex);
5268 
5269  Yetani::VectorWlOutput& output_vector = output_data.surface_output_map[wl_surface];
5270 
5271  struct wl_output* output_current = output_vector.front();
5272 
5273  if(output_current != wl_output)
5274  {
5275  return;
5276  }
5277 
5278  Yetani::Output& output = output_data.output_map.at(wl_output);
5279  Yetani::SizePixel new_size = surface_extent.size_pixel;
5280 
5281  if(surface_extent.preferred_unit == Yetani::SizeUnit::Millimeter)
5282  {
5283  auto p = yetani->convertMmToPixel(output, surface_extent.size_mm.width, surface_extent.size_mm.height);
5284  new_size = { p.first, p.second };
5285  }
5286  else if(surface_extent.preferred_unit == Yetani::SizeUnit::Percent)
5287  {
5288  auto p = yetani->convertPercentToPixel(output, surface_extent.size_percent.width, surface_extent.size_percent.height);
5289  new_size = { p.first, p.second };
5290  }
5291 
5292  if(new_size.width <= 0)
5293  {
5294  new_size.width = 1;
5295  }
5296 
5297  if(new_size.height <= 0)
5298  {
5299  new_size.height = 1;
5300  }
5301 
5302  yetani->surface_resize_mutex_map[wl_surface].lock();
5303  {
5304  surface_extent.size_pixel = new_size;
5305  surfaceCalculateSize(yetani, wl_surface, new_size);
5306  }
5307  yetani->surface_resize_mutex_map[wl_surface].unlock();
5308 }
5309 
5310 // }}}
5311 // {{{ Wayland : Seat
5312 
5345 void Yetani::seatDestroy(struct wl_seat*& wl_seat
5346  ) noexcept
5347 {
5348  Yetani::Seat& seat = seat_map[wl_seat];
5349 
5350  if(seat.wl_keyboard != nullptr)
5351  {
5352  wl_keyboard_release(seat.wl_keyboard);
5353  seat.wl_keyboard = nullptr;
5354  }
5355 
5356  if(seat.wl_pointer != nullptr)
5357  {
5358  wl_pointer_release(seat.wl_pointer);
5359  seat.wl_pointer = nullptr;
5360  }
5361 
5362  if(seat.wl_touch != nullptr)
5363  {
5364  wl_touch_release(seat.wl_touch);
5365  seat.wl_touch = nullptr;
5366  }
5367 
5368  seat_map.erase(wl_seat);
5369 
5370  wl_seat_release(wl_seat);
5371 
5372  wl_seat = nullptr;
5373 }
5374 
5375 // }}}
5376 // {{{ Wayland : Seat : Keyboard
5377 
5451 int32_t Yetani::keyRepeatDelay() const noexcept
5452 {
5453  return keyboard.repeat_delay;
5454 }
5455 
5456 
5465 int32_t Yetani::keyRepeatRate() const noexcept
5466 {
5467  return 1000 / keyboard.repeat_rate;
5468 }
5469 
5470 
5474 void Yetani::keyboardDestroy(Yetani::Keyboard& keyboard
5475  ) noexcept
5476 {
5477  if(keyboard.keymap != nullptr)
5478  {
5479  munmap(keyboard.keymap, keyboard.keymap_size);
5480  }
5481 
5482  keyboard.wl_surface = nullptr;
5483  keyboard.event = nullptr;
5484  keyboard.modifier = { 0 };
5485  keyboard.repeat_rate = 0;
5486  keyboard.repeat_delay = {};
5487  keyboard.keymap = nullptr;
5488  keyboard.keymap_size = 0;
5489 }
5490 
5491 
5498 void Yetani::keyboardRepeat(Yetani::Keyboard& keyboard
5499  ) noexcept
5500 {
5501  auto now = std::chrono::steady_clock::now();
5502 
5503  for(auto& iter : keyboard.repeat_map)
5504  {
5505  Yetani::KeyRepeatData& key_repeat = iter.second;
5506 
5507  if(now >= key_repeat.trigger_time)
5508  {
5509  uint32_t key_code = iter.first;
5510 
5511  Yetani::Key key =
5512  { .time = key_repeat.base_time
5513  , .code = key_code
5514  , .state = Yetani::KeyState::Repeat
5515  };
5516 
5517  keyboard.event->on_key(key, keyboard.modifier);
5518 
5519  key_repeat.trigger_time = now
5520  + std::chrono::milliseconds(keyboard.repeat_rate)
5521  - (now - key_repeat.trigger_time)
5522  ;
5523  key_repeat.base_time += keyboard.repeat_rate;
5524  }
5525  }
5526 }
5527 
5528 
5536 void Yetani::keyboardRepeatAdd(Yetani::Keyboard& keyboard
5537  , uint32_t key_code
5538  , uint32_t time
5539  ) noexcept
5540 {
5541  auto trigger_time = std::chrono::steady_clock::now()
5542  + std::chrono::milliseconds(keyboard.repeat_delay)
5543  ;
5544 
5545  keyboard.repeat_map[key_code] =
5546  { .trigger_time = trigger_time
5547  , .base_time = time + keyboard.repeat_delay
5548  };
5549 }
5550 
5551 
5558 void Yetani::keyboardRepeatReleaseAll(Yetani::Keyboard& keyboard
5559  ) noexcept
5560 {
5561  while(keyboard.repeat_map.empty() == false)
5562  {
5563  auto iter = keyboard.repeat_map.begin();
5564 
5565  uint32_t key_code = iter->first;
5566 
5567  Yetani::Key key =
5568  { .time = 0
5569  , .code = key_code
5570  , .state = Yetani::KeyState::Released
5571  };
5572 
5573  keyboard.event->on_key(key, keyboard.modifier);
5574 
5575  keyboard.repeat_map.erase(iter);
5576  }
5577 }
5578 
5579 
5586 void Yetani::keyboardRepeatRemove(Yetani::Keyboard& keyboard
5587  , uint32_t key_code
5588  ) noexcept
5589 {
5590  keyboard.repeat_map.erase(key_code);
5591 }
5592 
5593 // }}}
5594 // {{{ Wayland : Seat : Pointer
5595 
5611 void Yetani::pointerClear(Yetani::Pointer& pointer
5612  ) noexcept
5613 {
5614  pointer.enter_surface = nullptr;
5615  pointer.enter_point = { 0, 0, 0 };
5616  pointer.leave_surface = nullptr;
5617  pointer.motion_point = { 0, 0, 0 };
5618  pointer.button_event_code = 0;
5619  pointer.button_is_pressed = false;
5620  pointer.button_time = 0;
5621  pointer.axis.time = 0;
5622  pointer.axis.type = Yetani::PointerAxisType::Unknown;
5623  pointer.axis.distance = 0;
5624  pointer.axis.source = Yetani::PointerAxisSource::Unknown;
5625  pointer.axis.steps = 0;
5626 }
5627 
5628 // }}}
5629 // {{{ Wayland : Surface
5630 
5668 void Yetani::surfaceCalculateSize(Yetani* yetani
5669  , struct wl_surface* wl_surface
5670  , const Yetani::SizePixel& size
5671  ) noexcept
5672 {
5673  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
5674  surface_size.width = size.width;
5675  surface_size.height = size.height;
5676  surface_size.stride = size.width * surface_size.bytes_per_pixel;
5677  surface_size.in_bytes = surface_size.stride * surface_size.height;
5678 
5679  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5680  surface_frame.width = size.width;
5681  surface_frame.height = size.height;
5682 }
5683 
5684 
5702 struct wl_surface* Yetani::surfaceCreate(Yetani* yetani
5703  , const wl_shm_format pixel_format
5704  , const Yetani::SizePixel& size
5705  , Yetani::Window::Memory& window_memory
5706  ) noexcept
5707 {
5708  struct wl_surface* wl_surface = wl_compositor_create_surface(yetani->compositor);
5709 
5710  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
5711  surface_size.pixel_format = pixel_format;
5712  surface_size.bytes_per_pixel = shmFormatBytesPerPixel(pixel_format);
5713 
5714  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5715  surface_frame.wl_surface = wl_surface;
5716  surface_frame.time_ms = 0;
5717 
5718  surfaceCalculateSize(yetani, wl_surface, size);
5719 
5720  surface_frame.buffer_next = bufferCreate(surface_size, &window_memory, &yetani->buffer);
5721 
5722  // A future configuration setting
5723  bool event_keyboard = true;
5724  if(event_keyboard)
5725  {
5726  yetani->keyboard.event_map[wl_surface] =
5727  { .on_enter = Lambda_DoNothing
5728  , .on_leave = Lambda_DoNothing
5729  , .on_key = LambdaKey_DoNothing
5730  };
5731  }
5732 
5733  // A future configuration setting
5734  bool event_pointer = true;
5735  if(event_pointer)
5736  {
5737  yetani->pointer.event_map[wl_surface] =
5738  { .on_axis = LambdaAxis_DoNothing
5739  , .on_axis_discrete = Lambda_DoNothing
5740  , .on_axis_source = Lambda_DoNothing
5741  , .on_axis_stop = Lambda_DoNothing
5742  , .on_button_mm = LambdaButtonMm_DoNothing
5743  , .on_button_percent = LambdaButtonPercent_DoNothing
5744  , .on_button_pixel = LambdaButtonPixel_DoNothing
5745  , .on_enter_mm = LambdaPointMm_DoNothing
5746  , .on_enter_percent = LambdaPointPercent_DoNothing
5747  , .on_enter_pixel = LambdaPointPixel_DoNothing
5748  , .on_leave = Lambda_DoNothing
5749  , .on_motion_mm = LambdaPointMm_DoNothing
5750  , .on_motion_percent = LambdaPointPercent_DoNothing
5751  , .on_motion_pixel = LambdaPointPixel_DoNothing
5752  };
5753  }
5754 
5755  yetani->surface_event_map[wl_surface] =
5756  { .on_size_mm_change = LambdaSizeMm_DoNothing
5757  , .on_size_percent_change = LambdaSizePercent_DoNothing
5758  , .on_size_pixel_change = LambdaSizePixel_DoNothing
5759  };
5760 
5761  wl_surface_add_listener(wl_surface
5762  , &surface_listener
5763  , yetani
5764  );
5765 
5766  return wl_surface;
5767 }
5768 
5769 
5775 void Yetani::surfaceDestroy(Yetani* yetani
5776  , struct wl_surface*& wl_surface
5777  ) noexcept
5778 {
5779  if(wl_surface == nullptr)
5780  {
5781  return;
5782  }
5783 
5784  if(yetani->surface_frame_map.contains(wl_surface))
5785  {
5786  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5787 
5788  struct wl_buffer* wl_buffer = nullptr;
5789  wl_buffer = surface_frame.buffer_next.exchange(nullptr);
5790 
5791  if(wl_buffer != nullptr)
5792  {
5793  bufferDestroy(wl_buffer);
5794  }
5795  }
5796 
5797  if(yetani->keyboard.event_map.contains(wl_surface))
5798  {
5799  yetani->keyboard.event_map.erase(wl_surface);
5800  }
5801 
5802  if(yetani->pointer.event_map.contains(wl_surface))
5803  {
5804  yetani->pointer.event_map.erase(wl_surface);
5805  }
5806 
5807  yetani->surface_size_map.erase(wl_surface);
5808  yetani->surface_frame_map.erase(wl_surface);
5809  yetani->surface_event_map.erase(wl_surface);
5810 
5811  yetani->cursorDetach(wl_surface);
5812 
5813  wl_surface_destroy(wl_surface);
5814  wl_surface = nullptr;
5815 }
5816 
5817 // }}}
5818 // {{{ Wayland : Listener Handlers : Buffer
5819 
5832 void Yetani::handlerBufferRelease(void* //data
5833  , struct wl_buffer* wl_buffer
5834  ) noexcept
5835 {
5836  Yetani::bufferDestroy(wl_buffer);
5837 }
5838 
5839 // }}}
5840 // {{{ Wayland : Listener Handlers : Keyboard
5841 
5845 void Yetani::handlerKeyboardEnter(void* data
5846  , struct wl_keyboard* // wl_keyboard
5847  , uint32_t // serial
5848  , struct wl_surface* wl_surface
5849  , struct wl_array* key_array
5850  ) noexcept
5851 {
5852  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5853 
5854  if(keyboard.wl_surface != nullptr)
5855  {
5856  keyboardRepeatReleaseAll(keyboard);
5857 
5858  keyboard.event->on_leave();
5859  }
5860 
5861  keyboard.wl_surface = wl_surface;
5862 
5863  if(keyboard.event_map.contains(wl_surface))
5864  {
5865  keyboard.event = &(keyboard.event_map[wl_surface]);
5866  }
5867  else
5868  {
5869  keyboard.event = &(keyboard.event_map[nullptr]);
5870  }
5871 
5872  keyboard.event->on_enter();
5873 
5874  if(key_array->size > 0)
5875  {
5876  Yetani::Key key =
5877  { .time = 0
5878  , .code = 0
5879  , .state = Yetani::KeyState::Pressed
5880  };
5881 
5882  ZAKERO_YETANI__ARRAY_FOR_EACH(uint32_t*, key_iter, key_array)
5883  {
5884  key.code = *key_iter;
5885 
5886  keyboard.event->on_key(key, keyboard.modifier);
5887 
5888  keyboardRepeatAdd(keyboard, key.code, 0);
5889  }
5890  }
5891 }
5892 
5893 
5897 void Yetani::handlerKeyboardKey(void* data
5898  , struct wl_keyboard* // wl_keyboard
5899  , uint32_t // serial
5900  , uint32_t time
5901  , uint32_t key_code
5902  , uint32_t state
5903  ) noexcept
5904 {
5905  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5906 
5907  Yetani::Key key =
5908  { .time = time
5909  , .code = key_code
5910  , .state = (state == WL_KEYBOARD_KEY_STATE_PRESSED)
5911  ? Yetani::KeyState::Pressed
5912  : Yetani::KeyState::Released
5913  };
5914 
5915  keyboard.event->on_key(key, keyboard.modifier);
5916 
5917  if(key.state == Yetani::KeyState::Pressed
5918  && keyboard.repeat_rate > 0
5919  )
5920  {
5921  keyboardRepeatAdd(keyboard, key_code, time);
5922  }
5923  else if(key.state == Yetani::KeyState::Released)
5924  {
5925  keyboardRepeatRemove(keyboard, key_code);
5926  }
5927 }
5928 
5929 
5933 void Yetani::handlerKeyboardKeymap(void* data
5934  , struct wl_keyboard* // wl_keyboard
5935  , uint32_t format
5936  , int32_t fd
5937  , uint32_t size
5938  ) noexcept
5939 {
5940  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5941 
5942  if(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
5943  {
5944  if(keyboard.keymap != nullptr)
5945  {
5946  munmap(keyboard.keymap
5947  , keyboard.keymap_size
5948  );
5949  }
5950 
5951  keyboard.keymap = (char*)mmap(nullptr
5952  , size
5953  , PROT_READ
5954  , MAP_NORESERVE | MAP_PRIVATE
5955  , fd
5956  , 0
5957  );
5958  keyboard.keymap_size = size;
5959  }
5960  else // (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP)
5961  {
5962  if(keyboard.keymap != nullptr)
5963  {
5964  munmap(keyboard.keymap
5965  , keyboard.keymap_size
5966  );
5967 
5968  keyboard.keymap = nullptr;
5969  keyboard.keymap_size = 0;
5970  }
5971  }
5972 }
5973 
5974 
5978 void Yetani::handlerKeyboardLeave(void* data
5979  , struct wl_keyboard* // wl_keyboard
5980  , uint32_t // serial
5981  , struct wl_surface* wl_surface
5982  ) noexcept
5983 {
5984  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5985 
5986  if(keyboard.wl_surface == wl_surface)
5987  {
5988  keyboardRepeatReleaseAll(keyboard);
5989 
5990  keyboard.event->on_leave();
5991 
5992  keyboard.event = &(keyboard.event_map[nullptr]);
5993  keyboard.wl_surface = nullptr;
5994  }
5995 }
5996 
5997 
6001 void Yetani::handlerKeyboardModifiers(void* data
6002  , struct wl_keyboard* // wl_keyboard
6003  , uint32_t // serial
6004  , uint32_t mods_pressed
6005  , uint32_t mods_latched
6006  , uint32_t mods_locked
6007  , uint32_t group
6008  ) noexcept
6009 {
6010  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
6011 
6012  keyboard.modifier.pressed = mods_pressed;
6013  keyboard.modifier.latched = mods_latched;
6014  keyboard.modifier.locked = mods_locked;
6015  keyboard.modifier.group = group;
6016 }
6017 
6018 
6022 void Yetani::handlerKeyboardRepeatInfo(void* data
6023  , struct wl_keyboard* // wl_keyboard
6024  , int32_t rate
6025  , int32_t delay
6026  ) noexcept
6027 {
6028  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
6029 
6030  keyboard.repeat_delay = delay;
6031  keyboard.repeat_rate = 1000 / rate;
6032 }
6033 
6034 // }}}
6035 // {{{ Wayland : Listener Handlers : Output
6036 
6040 void Yetani::handlerOutputDone(void* data
6041  , struct wl_output* wl_output
6042  ) noexcept
6043 {
6044  Yetani* yetani = (Yetani*)data;
6045  Yetani::Output& output = yetani->output_data.output_map[wl_output];
6046  Yetani::Output& changes = yetani->output_changes_map[wl_output];
6047  Yetani::OutputId output_id = yetani->output_data.wloutput_to_outputid[wl_output];
6048 
6076  output = changes;
6077  output.pixels_per_mm_horizontal = output.width / float(output.physical_width_mm);
6078  output.pixels_per_mm_vertical = output.height / float(output.physical_height_mm);
6079 
6080  ZAKERO_YETANI__DEBUG << "\n" << to_string(output) << "\n";
6081 
6082  switch(yetani->output_state_map[wl_output])
6083  {
6084  case Yetani::OutputState::Done:
6085  // Do Nothing
6086  break;
6087 
6088  case Yetani::OutputState::Added:
6089  yetani->on_output_add(output_id);
6090  break;
6091 
6092  case Yetani::OutputState::Changed:
6093  yetani->on_output_change(output_id);
6094 
6095  for(auto wl_surface : yetani->output_notify_surface_vector)
6096  {
6097  outputNotifySurface(yetani, wl_output, wl_surface);
6098  }
6099 
6100  break;
6101  }
6102 
6103  yetani->output_state_map[wl_output] = Yetani::OutputState::Done;
6104 }
6105 
6106 
6110 void Yetani::handlerOutputGeometry(void* data
6111  , struct wl_output* wl_output
6112  , int32_t x
6113  , int32_t y
6114  , int32_t physical_width
6115  , int32_t physical_height
6116  , int32_t subpixel
6117  , const char* make
6118  , const char* model
6119  , int32_t transform
6120  ) noexcept
6121 {
6122  Yetani* yetani = (Yetani*)data;
6123  Yetani::Output& output_changes = yetani->output_changes_map[wl_output];
6124 
6125  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6126  {
6127  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6128  }
6129 
6130  output_changes.x = x;
6131  output_changes.y = y;
6132  output_changes.physical_width_mm = physical_width;
6133  output_changes.physical_height_mm = physical_height;
6134  output_changes.subpixel = subpixel;
6135  output_changes.make = std::string(make);
6136  output_changes.model = std::string(model);
6137  output_changes.transform = transform;
6138 }
6139 
6140 
6144 void Yetani::handlerOutputMode(void* data
6145  , struct wl_output* wl_output
6146  , uint32_t flags
6147  , int32_t width
6148  , int32_t height
6149  , int32_t refresh
6150  ) noexcept
6151 {
6152  Yetani* yetani = (Yetani*)data;
6153  Yetani::Output& output_changes = yetani->output_changes_map[wl_output];
6154 
6155  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6156  {
6157  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6158  }
6159 
6160  output_changes.flags = flags;
6161  output_changes.width = width;
6162  output_changes.height = height;
6163  output_changes.refresh_mHz = refresh;
6164 }
6165 
6166 
6170 void Yetani::handlerOutputScale(void* data
6171  , struct wl_output* wl_output
6172  , int32_t factor
6173  ) noexcept
6174 {
6175  Yetani* yetani = (Yetani*)data;
6176  Output& output_changes = yetani->output_changes_map[wl_output];
6177 
6178  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6179  {
6180  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6181  }
6182 
6183  output_changes.scale_factor = factor;
6184 }
6185 
6186 // }}}
6187 // {{{ Wayland : Listener Handlers : Pointer
6188 
6192 void Yetani::handlerPointerAxis(void* data
6193  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6194  , uint32_t time
6195  , uint32_t axis
6196  , wl_fixed_t value
6197  ) noexcept
6198 {
6199  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6200 
6201  pointer.axis.time = time;
6202  pointer.axis.distance = (float)wl_fixed_to_double(value);
6203 
6204  if(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
6205  {
6206  pointer.axis.type = Yetani::PointerAxisType::Horizontal;
6207  }
6208  else if(axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
6209  {
6210  pointer.axis.type = Yetani::PointerAxisType::Vertical;
6211  }
6212  else
6213  {
6214  pointer.axis.type = Yetani::PointerAxisType::Unknown;
6215  }
6216 }
6217 
6218 
6222 void Yetani::handlerPointerAxisDiscrete(void* data
6223  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6224  , uint32_t //axis ///< The axis
6225  , int32_t discrete
6226  ) noexcept
6227 {
6228  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6229 
6230  pointer.axis.steps = discrete;
6231 }
6232 
6233 
6237 void Yetani::handlerPointerAxisSource(void* data
6238  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6239  , uint32_t axis_source
6240  ) noexcept
6241 {
6242  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6243 
6244  switch(axis_source)
6245  {
6246  case WL_POINTER_AXIS_SOURCE_WHEEL:
6247  pointer.axis.source = Yetani::PointerAxisSource::Wheel;
6248  break;
6249 
6250  case WL_POINTER_AXIS_SOURCE_FINGER:
6251  pointer.axis.source = Yetani::PointerAxisSource::Finger;
6252  break;
6253 
6254  case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
6255  pointer.axis.source = Yetani::PointerAxisSource::Continuous;
6256  break;
6257 
6258  case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
6259  pointer.axis.source = Yetani::PointerAxisSource::Wheel_Tilt;
6260  break;
6261 
6262  default:
6263  pointer.axis.source = Yetani::PointerAxisSource::Unknown;
6264  }
6265 }
6266 
6267 
6271 void Yetani::handlerPointerAxisStop(void*
6272  , struct wl_pointer*
6273  , uint32_t
6274  , uint32_t
6275  ) noexcept
6276 {
6277  // --- Ignored ---
6278  //
6279  // Wayland documentation suggests that the "axis stop" can be used for
6280  // kinetic scrolling or to determine when one axis motions begins anew.
6281  //
6282  // This is not needed.
6283  // - For kinetic scrolling: Have the default scrolling be kinetic and
6284  // treat axis input as a new (or additive) velocity.
6285  // - For separation of axis motion, why? If there is a pause in the
6286  // motion, that reflects the user input.
6287 }
6288 
6289 
6293 void Yetani::handlerPointerButton(void* data
6294  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6295  , uint32_t //serial ///< The Event Id
6296  , uint32_t time
6297  , uint32_t button
6298  , uint32_t state
6299  ) noexcept
6300 {
6301  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6302 
6303  pointer.button.code = button;
6304  pointer.button_time = time;
6305 
6306  if(state == WL_POINTER_BUTTON_STATE_RELEASED)
6307  {
6308  pointer.button.state = Yetani::PointerButtonState::Released;
6309  }
6310  else if(state == WL_POINTER_BUTTON_STATE_PRESSED)
6311  {
6312  pointer.button.state = Yetani::PointerButtonState::Pressed;
6313  }
6314 }
6315 
6316 
6320 void Yetani::handlerPointerEnter(void* data
6321  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6322  , uint32_t serial
6323  , struct wl_surface* wl_surface
6324  , wl_fixed_t surface_x
6325  , wl_fixed_t surface_y
6326  ) noexcept
6327 {
6328  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6329 
6330  pointer.enter_serial = serial;
6331  pointer.enter_surface = wl_surface;
6332 
6333  pointer.enter_point =
6334  { .time = 0
6335  , .x = wl_fixed_to_int(surface_x)
6336  , .y = wl_fixed_to_int(surface_y)
6337  };
6338 }
6339 
6340 
6344 void Yetani::handlerPointerFrame(void* data
6345  , struct wl_pointer* wl_pointer
6346  ) noexcept
6347 {
6348  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6349  Yetani* yetani = pointer.yetani;
6350 
6351  if(pointer.enter_surface != nullptr)
6352  {
6353  if(pointer.wl_surface != nullptr)
6354  {
6355  yetani->cursorLeave(pointer.wl_surface);
6356  pointer.event_map[pointer.wl_surface].on_leave();
6357  }
6358 
6359  yetani->cursorEnter(wl_pointer
6360  , pointer.enter_serial
6361  , pointer.enter_surface
6362  );
6363 
6364  pointer.wl_surface = pointer.enter_surface;
6365  pointer.point_pixel = pointer.enter_point;
6366 
6367  if(pointer.event_map.contains(pointer.wl_surface))
6368  {
6369  pointer.event = &(pointer.event_map[pointer.wl_surface]);
6370  }
6371  else
6372  {
6373  pointer.event = &(pointer.event_map[nullptr]);
6374  }
6375 
6376  yetani->convertPixel(pointer.enter_surface
6377  , pointer.point_pixel.x , pointer.point_pixel.y
6378  , pointer.point_mm.x , pointer.point_mm.y
6379  , pointer.point_percent.x, pointer.point_percent.y
6380  );
6381 
6382  pointer.event->on_enter_pixel(pointer.point_pixel
6383  , yetani->keyboard.modifier
6384  );
6385  pointer.event->on_enter_mm(pointer.point_mm
6386  , yetani->keyboard.modifier
6387  );
6388  pointer.event->on_enter_percent(pointer.point_percent
6389  , yetani->keyboard.modifier
6390  );
6391  }
6392 
6393  if((pointer.motion_point.time != 0)
6394  && (pointer.wl_surface != nullptr)
6395  )
6396  {
6397  pointer.point_pixel = pointer.motion_point;
6398 
6399  yetani->convertPixel(pointer.wl_surface
6400  , pointer.point_pixel.x , pointer.point_pixel.y
6401  , pointer.point_mm.x , pointer.point_mm.y
6402  , pointer.point_percent.x, pointer.point_percent.y
6403  );
6404  pointer.point_mm.time = pointer.point_pixel.time;
6405  pointer.point_percent.time = pointer.point_pixel.time;
6406 
6407  pointer.event->on_motion_pixel(pointer.point_pixel
6408  , yetani->keyboard.modifier
6409  );
6410  pointer.event->on_motion_mm(pointer.point_mm
6411  , yetani->keyboard.modifier
6412  );
6413  pointer.event->on_motion_percent(pointer.point_percent
6414  , yetani->keyboard.modifier
6415  );
6416  }
6417 
6418  if((pointer.button_time != 0)
6419  && (pointer.wl_surface != nullptr)
6420  )
6421  {
6422  pointer.point_mm.time = pointer.button_time;
6423  pointer.point_percent.time = pointer.button_time;
6424  pointer.point_pixel.time = pointer.button_time;
6425 
6426  pointer.event->on_button_pixel(pointer.button
6427  , pointer.point_pixel
6428  , yetani->keyboard.modifier
6429  );
6430  pointer.event->on_button_mm(pointer.button
6431  , pointer.point_mm
6432  , yetani->keyboard.modifier
6433  );
6434  pointer.event->on_button_percent(pointer.button
6435  , pointer.point_percent
6436  , yetani->keyboard.modifier
6437  );
6438  }
6439 
6440  if((pointer.axis.time != 0)
6441  && (pointer.wl_surface != nullptr)
6442  )
6443  {
6444  pointer.event->on_axis(pointer.axis
6445  , yetani->keyboard.modifier
6446  );
6447  }
6448 
6449  if((pointer.leave_surface != nullptr)
6450  && (pointer.leave_surface == pointer.wl_surface)
6451  )
6452  {
6453  yetani->cursorLeave(pointer.leave_surface);
6454 
6455  pointer.event->on_leave();
6456 
6457  pointer.event = &(pointer.event_map[nullptr]);
6458  pointer.wl_surface = nullptr;
6459  }
6460 
6461  pointerClear(pointer);
6462 }
6463 
6464 
6468 void Yetani::handlerPointerLeave(void* data
6469  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6470  , uint32_t //serial ///< The Event Id
6471  , struct wl_surface* wl_surface
6472  ) noexcept
6473 {
6474  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6475 
6476  pointer.leave_surface = wl_surface;
6477 }
6478 
6479 
6483 void Yetani::handlerPointerMotion(void* data
6484  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6485  , uint32_t time
6486  , wl_fixed_t surface_x
6487  , wl_fixed_t surface_y
6488  ) noexcept
6489 {
6490  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6491 
6492  pointer.motion_point =
6493  { .time = time
6494  , .x = wl_fixed_to_int(surface_x)
6495  , .y = wl_fixed_to_int(surface_y)
6496  };
6497 }
6498 
6499 // }}}
6500 // {{{ Wayland : Listener Handlers : Registry
6501 
6505 void Yetani::handlerRegistryGlobal(void* data
6506  , struct wl_registry* registry
6507  , uint32_t id
6508  , const char* interface
6509  , uint32_t version
6510  ) noexcept
6511 {
6512  Yetani* yetani = (Yetani*)data;
6513 
6514  std::string_view interface_name(interface);
6515  ZAKERO_YETANI__DEBUG_VAR(interface_name);
6516 
6517  if(interface_name == wl_compositor_interface.name)
6518  {
6519  yetani->compositor = (struct wl_compositor*)
6520  wl_registry_bind(registry
6521  , id
6522  , &wl_compositor_interface
6523  , 1
6524  );
6525 
6526  return;
6527  }
6528 
6529  if(interface_name == wl_output_interface.name)
6530  {
6531  struct wl_output* wl_output = (struct wl_output*)wl_registry_bind(registry
6532  , id
6533  , &wl_output_interface
6534  , 2
6535  );
6536 
6537  yetani->output_data.wloutput_to_outputid[wl_output] = id;
6538  yetani->output_data.outputid_to_wloutput[id] = wl_output;
6539  yetani->output_data.output_map[wl_output] = {};
6540  yetani->output_changes_map[wl_output] = {};
6541  yetani->output_state_map[wl_output] = Yetani::OutputState::Added;
6542 
6543  wl_output_add_listener(wl_output
6544  , &Yetani::output_listener
6545  , yetani
6546  );
6547 
6548  return;
6549  }
6550 
6551  if(interface_name == wl_seat_interface.name)
6552  {
6553  yetani->seat = (struct wl_seat*)
6554  wl_registry_bind(registry
6555  , id
6556  , &wl_seat_interface
6557  , version
6558  );
6559 
6560  yetani->id_to_seat[id] = yetani->seat;
6561 
6562  wl_seat_add_listener(yetani->seat
6563  , &yetani->seat_listener
6564  , yetani
6565  );
6566 
6567  return;
6568  }
6569 
6570  if(interface_name == wl_shm_interface.name)
6571  {
6572  yetani->shm = (struct wl_shm*)
6573  wl_registry_bind(registry
6574  , id
6575  , &wl_shm_interface
6576  , version
6577  );
6578 
6579  wl_shm_add_listener(yetani->shm
6580  , &yetani->shm_listener
6581  , yetani
6582  );
6583 
6584  return;
6585  }
6586 
6587  if(interface_name == xdg_wm_base_interface.name)
6588  {
6589  yetani->xdg_wm_base = (struct xdg_wm_base*)
6590  wl_registry_bind(registry
6591  , id
6592  , &xdg_wm_base_interface
6593  , 1
6594  );
6595 
6596  xdg_wm_base_add_listener(yetani->xdg_wm_base
6597  , &yetani->xdg_wm_base_listener
6598  , yetani
6599  );
6600  }
6601 
6602  if(interface_name == zxdg_decoration_manager_v1_interface.name)
6603  {
6604  yetani->decoration_manager = (struct zxdg_decoration_manager_v1*)
6605  wl_registry_bind(registry
6606  , id
6607  , &zxdg_decoration_manager_v1_interface
6608  , 1
6609  );
6610  ZAKERO_YETANI__DEBUG << "--- Using UNSTABLE Decoration Manager ---\n";
6611  }
6612 }
6613 
6614 
6618 void Yetani::handlerRegistryRemove(void* data
6619  , struct wl_registry* //registry ///< The registry object
6620  , uint32_t id
6621  ) noexcept
6622 {
6623  Yetani* yetani = (Yetani*)data;
6624 
6625  printf("Got a registry remove event for id %d\n", id);
6626 
6627  // Output
6628  {
6629  std::lock_guard<std::mutex> lock(yetani->output_data.mutex);
6630 
6631  if(yetani->output_data.outputid_to_wloutput.contains(id))
6632  {
6633  struct wl_output* wl_output = yetani->output_data.outputid_to_wloutput[id];
6634 
6635  yetani->output_data.outputid_to_wloutput.erase(id);
6636  yetani->output_data.wloutput_to_outputid.erase(wl_output);
6637 
6638  yetani->output_changes_map.erase(wl_output);
6639  yetani->output_state_map.erase(wl_output);
6640 
6641  yetani->on_output_remove(id);
6642  yetani->output_data.output_map.erase(wl_output);
6643 
6644  return;
6645  }
6646  }
6647 
6648  // Seat
6649  {
6650  if(yetani->id_to_seat.contains(id))
6651  {
6652  struct wl_seat* wl_seat = yetani->id_to_seat[id];
6653 
6654  yetani->seatDestroy(wl_seat);
6655 
6656  yetani->id_to_seat.erase(id);
6657  }
6658  }
6659 }
6660 
6661 // }}}
6662 // {{{ Wayland : Listener Handlers : Seat
6663 
6671 void Yetani::handlerSeatCapabilities(void* data
6672  , struct wl_seat* wl_seat
6673  , uint32_t capabilities
6674  ) noexcept
6675 {
6676  ZAKERO_YETANI__DEBUG_VAR((uint64_t)wl_seat);
6677 
6678  Yetani* yetani = (Yetani*)data;
6679  Yetani::Seat& seat = yetani->seat_map[wl_seat];
6680 
6681  seat.version = wl_seat_get_version(wl_seat);
6682 
6683  if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD)
6684  {
6685  ZAKERO_YETANI__DEBUG << "-- Got a keyboard device --\n";
6686 
6687  yetani->keyboard.event_map[nullptr] =
6688  { .on_enter = Lambda_DoNothing
6689  , .on_leave = Lambda_DoNothing
6690  , .on_key = LambdaKey_DoNothing
6691  };
6692 
6693  yetani->keyboard.event = &(yetani->keyboard.event_map[nullptr]);
6694 
6695  seat.wl_keyboard = wl_seat_get_keyboard(wl_seat);
6696 
6697  wl_keyboard_add_listener(seat.wl_keyboard
6698  , &Yetani::keyboard_listener
6699  , &yetani->keyboard
6700  );
6701  }
6702 
6703  if(capabilities & WL_SEAT_CAPABILITY_POINTER)
6704  {
6705  ZAKERO_YETANI__DEBUG << "-- Got a pointer device --\n";
6706 
6707  yetani->pointer.yetani = yetani;
6708 
6709  yetani->pointer.event_map[nullptr] =
6710  { .on_axis = LambdaAxis_DoNothing
6711  , .on_axis_discrete = Lambda_DoNothing
6712  , .on_axis_source = Lambda_DoNothing
6713  , .on_axis_stop = Lambda_DoNothing
6714  , .on_button_mm = LambdaButtonMm_DoNothing
6715  , .on_button_percent = LambdaButtonPercent_DoNothing
6716  , .on_button_pixel = LambdaButtonPixel_DoNothing
6717  , .on_enter_mm = LambdaPointMm_DoNothing
6718  , .on_enter_percent = LambdaPointPercent_DoNothing
6719  , .on_enter_pixel = LambdaPointPixel_DoNothing
6720  , .on_leave = Lambda_DoNothing
6721  , .on_motion_mm = LambdaPointMm_DoNothing
6722  , .on_motion_percent = LambdaPointPercent_DoNothing
6723  , .on_motion_pixel = LambdaPointPixel_DoNothing
6724  };
6725 
6726  yetani->pointer.event = &(yetani->pointer.event_map[nullptr]);
6727 
6728  seat.wl_pointer = wl_seat_get_pointer(wl_seat);
6729 
6730  wl_pointer_add_listener(seat.wl_pointer
6731  , &Yetani::pointer_listener
6732  , &yetani->pointer
6733  );
6734  }
6735 
6736  if(capabilities & WL_SEAT_CAPABILITY_TOUCH)
6737  {
6738  ZAKERO_YETANI__DEBUG << "-- Got a touch device --\n";
6739  seat.wl_touch = wl_seat_get_touch(wl_seat);
6740 
6741  //wl_touch_add_listener(seat.wl_touch
6742  // , &Yetani::touch_listener
6743  // , data
6744  // );
6745  }
6746 }
6747 
6748 
6752 void Yetani::handlerSeatName(void* data
6753  , struct wl_seat* wl_seat
6754  , const char* name
6755  ) noexcept
6756 {
6757  ZAKERO_YETANI__DEBUG_VAR((uint64_t)wl_seat);
6758  ZAKERO_YETANI__DEBUG_VAR(name);
6759 
6760  Yetani* yetani = (Yetani*)data;
6761 
6762  yetani->seat_map[wl_seat].name = name;
6763 }
6764 
6765 // }}}
6766 // {{{ Wayland : Listener Handlers : SHM
6767 
6771 void Yetani::handlerShmFormat(void* data
6772  , struct wl_shm* /* Unused */
6773  , uint32_t value
6774  ) noexcept
6775 {
6776  Yetani* yetani = (Yetani*)data;
6777 
6778  wl_shm_format format = (wl_shm_format)value;
6779 
6780  if(vectorContains(yetani->shm_format_vector, format))
6781  {
6782  return;
6783  }
6784 
6785  yetani->shm_format_vector.push_back(format);
6786 }
6787 
6788 // }}}
6789 // {{{ Wayland : Listener Handlers : Surface
6790 
6794 void Yetani::handlerSurfaceEnter(void* data
6795  , struct wl_surface* wl_surface
6796  , struct wl_output* wl_output
6797  ) noexcept
6798 {
6799  //ZAKERO_YETANI__DEBUG << "-------------------------------------------\n";
6800  //ZAKERO_YETANI__DEBUG_VAR(data);
6801  //ZAKERO_YETANI__DEBUG_VAR(wl_surface);
6802  //ZAKERO_YETANI__DEBUG_VAR(wl_output);
6803 
6804  Yetani* yetani = (Yetani*)data;
6805  Yetani::OutputData& output_data = yetani->output_data;
6806 
6807  output_data.mutex.lock();
6808  output_data.surface_output_map[wl_surface].push_back(wl_output);
6809  output_data.mutex.unlock();
6810 }
6811 
6812 
6816 void Yetani::handlerSurfaceLeave(void* data
6817  , struct wl_surface* wl_surface
6818  , struct wl_output* wl_output
6819  ) noexcept
6820 {
6821  //ZAKERO_YETANI__DEBUG << "-------------------------------------------\n";
6822  //ZAKERO_YETANI__DEBUG_VAR(data);
6823  //ZAKERO_YETANI__DEBUG_VAR(wl_surface);
6824  //ZAKERO_YETANI__DEBUG_VAR(wl_output);
6825 
6826  Yetani* yetani = (Yetani*)data;
6827 
6828  Yetani::OutputData& output_data = yetani->output_data;
6829  std::lock_guard<std::mutex> lock(output_data.mutex);
6830 
6831  Yetani::VectorWlOutput& output_vector = output_data.surface_output_map[wl_surface];
6832 
6833  // Save the current wl_output device id
6834  struct wl_output* current_output = output_vector.front();
6835 
6836  // Remove the wl_output device id
6837  zakero::vectorErase(output_vector, wl_output);
6838 
6839  // Check if the current wl_output device id was removed
6840  if(current_output == output_vector.front())
6841  {
6842  // Current wl_output device was not removed
6843  // so nothing to do.
6844 
6845  return;
6846  }
6847 
6848  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
6849 
6850  if(surface_extent.preferred_unit == Yetani::SizeUnit::Pixel)
6851  {
6852  return;
6853  }
6854 
6855  // Convert the relative window size from the old wl_output device
6856  // to the new wl_output device.
6857 
6858  current_output = output_vector.front();
6859 
6860  Yetani::Output& output = output_data.output_map.at(current_output);
6861  Yetani::SizePixel new_size;
6862 
6863  if(surface_extent.preferred_unit == Yetani::SizeUnit::Millimeter)
6864  {
6865  auto p = yetani->convertMmToPixel(output
6866  , surface_extent.size_mm.width
6867  , surface_extent.size_mm.height
6868  );
6869 
6870  new_size = { p.first, p.second };
6871  }
6872  else // if(surface_extent.preferred_unit == Yetani::SizeUnit::Percent)
6873  {
6874  auto p = yetani->convertPercentToPixel(output
6875  , surface_extent.size_percent.width
6876  , surface_extent.size_percent.height
6877  );
6878 
6879  new_size = { p.first, p.second };
6880  }
6881 
6882  if(new_size.width <= 0)
6883  {
6884  new_size.width = 1;
6885  }
6886 
6887  if(new_size.height <= 0)
6888  {
6889  new_size.height = 1;
6890  }
6891 
6892  if((new_size.width != surface_extent.size_pixel.width)
6893  && (new_size.height != surface_extent.size_pixel.height)
6894  )
6895  {
6896  yetani->surface_resize_mutex_map[wl_surface].lock();
6897  {
6898  XdgSurface& surface = yetani->xdg_surface_map[wl_surface];
6899 
6900  surface_extent.size_pixel = new_size;
6901  surfaceCalculateSize(surface.yetani, surface.wl_surface, new_size);
6902  }
6903  yetani->surface_resize_mutex_map[wl_surface].unlock();
6904 
6905  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
6906  event.on_size_pixel_change(surface_extent.size_pixel);
6907  }
6908 }
6909 
6910 // }}}
6911 // {{{ Wayland : Listener Handlers : SwapBuffers
6912 
6916 void Yetani::handlerSwapBuffers(void* data
6917  , struct wl_callback* callback
6918  , uint32_t time_ms
6919  ) noexcept
6920 {
6921  Yetani::SurfaceFrame* surface_frame = (Yetani::SurfaceFrame*)data;
6922 
6923  wl_callback_destroy(callback);
6924 
6925  callback = wl_surface_frame(surface_frame->wl_surface);
6926 
6927  wl_callback_add_listener(callback
6928  , &frame_callback_listener
6929  , data
6930  );
6931 
6932  struct wl_buffer* wl_buffer = surface_frame->buffer_next.exchange(nullptr);
6933  if(wl_buffer != nullptr)
6934  {
6935  wl_buffer_add_listener(wl_buffer
6936  , &Yetani::buffer_listener
6937  , wl_buffer_get_user_data(wl_buffer)
6938  );
6939 
6940  surface_frame->time_ms = time_ms;
6941 
6942  wl_surface_attach(surface_frame->wl_surface, wl_buffer, 0, 0);
6943 
6944  wl_surface_damage(surface_frame->wl_surface
6945  , 0, 0
6946  , surface_frame->width, surface_frame->height
6947  );
6948  }
6949 
6950  wl_surface_commit(surface_frame->wl_surface);
6951 }
6952 
6953 // }}}
6954 // {{{ Wayland : Listener Handlers (Unstable)
6955 
6956 
6957 // }}}
6958 // {{{ XDG
6959 
6972 Yetani::WindowMode Yetani::toWindowMode(const Yetani::XdgState state
6973  ) noexcept
6974 {
6975  switch(state)
6976  {
6977  case Yetani::XdgState::Toplevel_Window_Fullscreen:
6978  return Yetani::WindowMode::Fullscreen;
6979 
6980  case Yetani::XdgState::Toplevel_Window_Maximized:
6981  return Yetani::WindowMode::Maximized;
6982 
6983  default:
6984  case Yetani::XdgState::Toplevel_Window_Normal:
6985  return Yetani::WindowMode::Normal;
6986  }
6987 }
6988 
6989 
6995 Yetani::XdgState Yetani::toXdgState(const Yetani::WindowMode window_mode
6996  ) noexcept
6997 {
6998  switch(window_mode)
6999  {
7000  case Yetani::WindowMode::Fullscreen:
7001  return Yetani::XdgState::Toplevel_Window_Fullscreen;
7002 
7003  case Yetani::WindowMode::Maximized:
7004  return Yetani::XdgState::Toplevel_Window_Maximized;
7005 
7006  default:
7007  case Yetani::WindowMode::Normal:
7008  return Yetani::XdgState::Toplevel_Window_Normal;
7009  }
7010 }
7011 
7012 // }}}
7013 // {{{ XDG : Surface
7014 
7035 struct xdg_surface* Yetani::xdgSurfaceCreate(struct wl_surface* wl_surface
7036  ) noexcept
7037 {
7038  XdgSurface& surface = xdg_surface_map[wl_surface];
7039 
7040  surface.yetani = this;
7041  surface.wl_surface = wl_surface;
7042 
7043  surface_extent_mutex.lock();
7044  {
7045  Yetani::SurfaceExtent& surface_extent = surface_extent_map[wl_surface];
7046 
7047  surface_extent.preferred_unit = Yetani::SizeUnit::Pixel;
7048  surface_extent.preferred_mm = { 160, 90 }; // 16:9 * 10mm
7049  surface_extent.preferred_percent = { 0.32, 0.18 }; // 16:9 * 0.02
7050  surface_extent.size_mm = { 160, 90 }; // 16:9 + 10mm
7051  surface_extent.size_percent = { 0.32, 0.18 }; // 16:9 * 0.02
7052  surface_extent.size_pixel = { 800, 450 }; // 16:9 * 50 pixels
7053  surface_extent.size_pixel_max = { 0, 0 }; // No maximum size
7054  surface_extent.size_pixel_min = { 0, 0 }; // No minimum size
7055  }
7056  surface_extent_mutex.unlock();
7057 
7058  output_notify_surface_vector.push_back(wl_surface);
7059 
7060  struct xdg_surface* xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base
7061  , wl_surface
7062  );
7063 
7064  xdg_state_change_mutex.lock();
7065  {
7066  xdg_state_change_map[xdg_surface] = {};
7067  }
7068  xdg_state_change_mutex.unlock();
7069 
7070  xdg_surface_add_listener(xdg_surface
7071  , &xdg_surface_listener
7072  , &surface
7073  );
7074 
7075  return xdg_surface;
7076 }
7077 
7078 
7087 void Yetani::xdgSurfaceDestroy(struct wl_surface* wl_surface
7088  , struct xdg_surface*& xdg_surface
7089  ) noexcept
7090 {
7091  if(xdg_surface)
7092  {
7093  xdg_surface_destroy(xdg_surface);
7094  }
7095 
7096  zakero::vectorErase(output_notify_surface_vector, wl_surface);
7097 
7098  if(xdg_surface_map.contains(wl_surface))
7099  {
7100  xdg_surface_map.erase(wl_surface);
7101  }
7102 
7103  xdg_state_change_mutex.lock();
7104  {
7105  if(xdg_state_change_map.contains(xdg_surface))
7106  {
7107  xdg_state_change_map.erase(xdg_surface);
7108  }
7109  }
7110  xdg_state_change_mutex.unlock();
7111 
7112  surface_extent_mutex.lock();
7113  {
7114  if(surface_extent_map.contains(wl_surface))
7115  {
7116  surface_extent_map.erase(wl_surface);
7117  }
7118  }
7119  surface_extent_mutex.unlock();
7120 
7121  xdg_surface = nullptr;
7122 }
7123 
7124 
7128 void Yetani::xdgSurfaceSetExtent(struct wl_surface* wl_surface
7129  , const Yetani::SizeUnit& size_unit
7130  , const Yetani::SizeMm& size_mm
7131  , const Yetani::SizePercent& size_percent
7132  , const Yetani::SizePixel& size_pixel
7133  ) noexcept
7134 {
7135  Yetani::SurfaceExtent& surface_extent = surface_extent_map[wl_surface];
7136 
7137  surface_extent.preferred_unit = size_unit;
7138  surface_extent.preferred_mm = size_mm;
7139  surface_extent.preferred_percent = size_percent;
7140  surface_extent.size_mm = size_mm;
7141  surface_extent.size_percent = size_percent;
7142  surface_extent.size_pixel = size_pixel;
7143  surface_extent.size_pixel_max = { 0, 0 };
7144  surface_extent.size_pixel_min = { 0, 0 };
7145 }
7146 
7147 // }}}
7148 // {{{ XDG : Toplevel
7149 
7188 struct xdg_toplevel* Yetani::xdgToplevelCreate(struct xdg_surface* xdg_surface
7189  ) noexcept
7190 {
7191  Yetani::XdgToplevel& toplevel = xdg_toplevel_map[xdg_surface];
7192 
7193  toplevel.close_request_lambda = Lambda_DoNothing;
7194  toplevel.state_change = &(xdg_state_change_map[xdg_surface]);
7195  toplevel.is_active = false;
7196  toplevel.window_state = Yetani::XdgState::Toplevel_Window_Normal;
7197  toplevel.is_active_lambda = LambdaBool_DoNothing;
7198  toplevel.window_state_lambda = LambdaWindowMode_DoNothing;
7199  toplevel.previous_size = { 0, 0 };
7200  toplevel.xdg_toplevel = nullptr;
7201 
7207  toplevel.state_change->push_back(Yetani::XdgState::Toplevel_Attach_Buffer);
7208 
7209  struct xdg_toplevel* xdg_toplevel = nullptr;
7210 
7211  xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
7212  toplevel.xdg_toplevel = xdg_toplevel;
7213 
7214  xdg_toplevel_add_listener(xdg_toplevel
7215  , &xdg_toplevel_listener
7216  , &toplevel
7217  );
7218 
7219  return xdg_toplevel;
7220 }
7221 
7222 
7229 void Yetani::xdgToplevelDestroy(struct xdg_surface* xdg_surface
7230  , struct xdg_toplevel*& xdg_toplevel
7231  ) noexcept
7232 {
7233  if(xdg_toplevel != nullptr)
7234  {
7235  xdg_toplevel_destroy(xdg_toplevel);
7236  }
7237 
7238  if(xdg_toplevel_map.contains(xdg_surface))
7239  {
7240  XdgToplevel& toplevel = xdg_toplevel_map[xdg_surface];
7241 
7242  toplevel.close_request_lambda = nullptr;
7243  toplevel.state_change = nullptr;
7244  toplevel.window_state = Yetani::XdgState::Unknown;
7245  toplevel.is_active = false;
7246  toplevel.is_active_lambda = nullptr;
7247  toplevel.window_state_lambda = nullptr;
7248 
7249  xdg_toplevel_map.erase(xdg_surface);
7250  }
7251 
7252  xdg_toplevel = nullptr;
7253 }
7254 
7255 
7265 void Yetani::xdgToplevelSizeChange(Yetani* yetani
7266  , struct wl_surface* wl_surface
7267  , const Yetani::SizePixel& size_pixel
7268  ) noexcept
7269 {
7270  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7271  Yetani::SizePixel new_size = surface_extent.size_pixel;
7272 
7273  if(((surface_extent.size_pixel_min.width == 0) || (size_pixel.width >= surface_extent.size_pixel_min.width))
7274  && ((surface_extent.size_pixel_max.width == 0) || (size_pixel.width <= surface_extent.size_pixel_max.width))
7275  )
7276  {
7277  new_size.width = size_pixel.width;
7278  }
7279 
7280  if(((surface_extent.size_pixel_min.height == 0) || (size_pixel.height >= surface_extent.size_pixel_min.height))
7281  && ((surface_extent.size_pixel_max.height == 0) || (size_pixel.height <= surface_extent.size_pixel_max.height))
7282  )
7283  {
7284  new_size.height = size_pixel.height;
7285  }
7286 
7287  if((new_size.width == surface_extent.size_pixel.width)
7288  && (new_size.height == surface_extent.size_pixel.height)
7289  )
7290  {
7291  return;
7292  }
7293 
7294  // Calculate Sizes
7295  Yetani::SizeMm size_mm;
7296  Yetani::SizePercent size_percent;
7297  yetani->convertPixel(wl_surface
7298  , size_pixel.width , size_pixel.height
7299  , size_mm.width , size_mm.height
7300  , size_percent.width, size_percent.height
7301  );
7302 
7303  yetani->surface_resize_mutex_map[wl_surface].lock();
7304  {
7305  surface_extent.size_pixel = new_size;
7306  surfaceCalculateSize(yetani, wl_surface, new_size);
7307  }
7308  yetani->surface_resize_mutex_map[wl_surface].unlock();
7309 
7310  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
7311  event.on_size_pixel_change(surface_extent.size_pixel);
7312  event.on_size_mm_change(surface_extent.size_mm);
7313  event.on_size_percent_change(surface_extent.size_percent);
7314 }
7315 
7316 
7320 void Yetani::xdgToplevelSizeMinMaxChange(Yetani* yetani
7321  , struct xdg_toplevel* xdg_toplevel
7322  , struct wl_surface* wl_surface
7323  , const Yetani::SizePixel& size_pixel_min
7324  , const Yetani::SizePixel& size_pixel_max
7325  ) noexcept
7326 {
7327  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7328 
7329  Yetani::SizePixel size_pixel = surface_extent.size_pixel;
7330  bool need_to_resize = false;
7331 
7332  if(size_pixel_max.width > 0
7333  && size_pixel_max.width < surface_extent.size_pixel.width
7334  )
7335  {
7336  need_to_resize = true;
7337  size_pixel.width = size_pixel_max.width;
7338  }
7339 
7340  if(size_pixel_max.height > 0
7341  && size_pixel_max.height < surface_extent.size_pixel.height
7342  )
7343  {
7344  need_to_resize = true;
7345  size_pixel.height = size_pixel_max.height;
7346  }
7347 
7348  if(size_pixel_min.width > 0
7349  && size_pixel_min.width > surface_extent.size_pixel.width
7350  )
7351  {
7352  need_to_resize = true;
7353  size_pixel.width = size_pixel_min.width;
7354  }
7355 
7356  if(size_pixel_min.height > 0
7357  && size_pixel_min.height > surface_extent.size_pixel.height
7358  )
7359  {
7360  need_to_resize = true;
7361  size_pixel.height = size_pixel_min.height;
7362  }
7363 
7364  if(need_to_resize)
7365  {
7366  xdg_toplevel_set_max_size(xdg_toplevel, 0, 0);
7367  xdg_toplevel_set_min_size(xdg_toplevel, 0, 0);
7368 
7369  yetani->surface_resize_mutex_map[wl_surface].lock();
7370  {
7371  surface_extent.size_pixel = size_pixel;
7372  surfaceCalculateSize(yetani, wl_surface, size_pixel);
7373  }
7374  yetani->surface_resize_mutex_map[wl_surface].unlock();
7375  }
7376 
7377  xdg_toplevel_set_min_size(xdg_toplevel
7378  , size_pixel_min.width
7379  , size_pixel_min.height
7380  );
7381 
7382  xdg_toplevel_set_max_size(xdg_toplevel
7383  , size_pixel_max.width
7384  , size_pixel_max.height
7385  );
7386 
7387  surface_extent.size_pixel_min = size_pixel_min;
7388  surface_extent.size_pixel_max = size_pixel_max;
7389 }
7390 
7391 
7395 void Yetani::xdgToplevelWindowChange(Yetani* yetani
7396  , struct wl_surface* wl_surface
7397  , Yetani::XdgToplevel& toplevel
7398  , const Yetani::XdgState window_state
7399  , const Yetani::SizePixel& size_pixel
7400  ) noexcept
7401 {
7402  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7403  Yetani::SizePixel new_size{1, 1};
7404 
7405  toplevel.window_state = window_state;
7406 
7407  if((toplevel.window_state == Yetani::XdgState::Toplevel_Window_Fullscreen)
7408  || (toplevel.window_state == Yetani::XdgState::Toplevel_Window_Maximized)
7409  )
7410  {
7411  if(toplevel.previous_size.width == 0)
7412  {
7413  xdg_toplevel_set_max_size(toplevel.xdg_toplevel, 0, 0);
7414  xdg_toplevel_set_min_size(toplevel.xdg_toplevel, 0, 0);
7415 
7416  toplevel.previous_size = surface_extent.size_pixel;
7417  }
7418 
7419  if((size_pixel.width != 0)
7420  && (size_pixel.height != 0)
7421  )
7422  {
7423  new_size = size_pixel;
7424  }
7425  }
7426  else if(toplevel.window_state == Yetani::XdgState::Toplevel_Window_Normal)
7427  {
7428  xdg_toplevel_set_max_size(toplevel.xdg_toplevel
7429  , surface_extent.size_pixel_max.width
7430  , surface_extent.size_pixel_max.height
7431  );
7432 
7433  xdg_toplevel_set_min_size(toplevel.xdg_toplevel
7434  , surface_extent.size_pixel_min.width
7435  , surface_extent.size_pixel_min.height
7436  );
7437 
7438  new_size = toplevel.previous_size;
7439  toplevel.previous_size.width = 0;
7440  }
7441 
7442  if(new_size == surface_extent.size_pixel)
7443  {
7444  return;
7445  }
7446 
7447  // Calculate Size
7448  Yetani::SizeMm size_mm;
7449  Yetani::SizePercent size_percent;
7450  yetani->convertPixel(wl_surface
7451  , size_pixel.width , size_pixel.height
7452  , size_mm.width , size_mm.height
7453  , size_percent.width, size_percent.height
7454  );
7455 
7456  yetani->surface_resize_mutex_map[wl_surface].lock();
7457  {
7458  surface_extent.size_mm = size_mm;
7459  surface_extent.size_percent = size_percent;
7460  surface_extent.size_pixel = new_size;
7461  surfaceCalculateSize(yetani, wl_surface, new_size);
7462  }
7463  yetani->surface_resize_mutex_map[wl_surface].unlock();
7464 
7465  toplevel.window_state_lambda(Yetani::toWindowMode(toplevel.window_state));
7466 
7467  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
7468  event.on_size_pixel_change(surface_extent.size_pixel);
7469  event.on_size_mm_change(surface_extent.size_mm);
7470  event.on_size_percent_change(surface_extent.size_percent);
7471 }
7472 
7473 // }}}
7474 // {{{ XDG : Decoration (Unstable)
7475 
7499 struct zxdg_toplevel_decoration_v1* Yetani::xdgDecorationCreate(struct xdg_surface* xdg_surface
7500  , struct xdg_toplevel* xdg_toplevel
7501  ) noexcept
7502 {
7503  if(decoration_manager == nullptr)
7504  {
7505  return nullptr;
7506  }
7507 
7508  /* *** From the xdg-decoration-unstable-v1 documentation ***
7509  *
7510  * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
7511  * buffer attached or committed is a client error.
7512  */
7513 
7514  zxdg_toplevel_decoration_v1* xdg_decoration =
7515  zxdg_decoration_manager_v1_get_toplevel_decoration(decoration_manager
7516  , xdg_toplevel
7517  );
7518 
7519  Yetani::XdgDecoration& decoration = xdg_decoration_map[xdg_surface];
7520  decoration.state_change = &(xdg_state_change_map[xdg_surface]);
7521  decoration.lambda = LambdaWindowDecorations_DoNothing;
7522  decoration.state = 0;
7523  decoration.is_present = false;
7524 
7525  zxdg_toplevel_decoration_v1_add_listener(xdg_decoration
7526  , &xdg_toplevel_decoration_listener
7527  , &decoration
7528  );
7529 
7530  return xdg_decoration;
7531 }
7532 
7533 
7539 void Yetani::xdgDecorationDestroy(struct xdg_surface* xdg_surface
7540  , struct xdg_toplevel* //xdg_toplevel ///< The XDG Toplevel
7541  , struct zxdg_toplevel_decoration_v1*& xdg_decoration
7542  ) noexcept
7543 {
7544  zxdg_toplevel_decoration_v1_destroy(xdg_decoration);
7545 
7546  if(xdg_decoration_map.contains(xdg_surface))
7547  {
7548  Yetani::XdgDecoration& decoration = xdg_decoration_map[xdg_surface];
7549  decoration.state_change = nullptr;
7550  decoration.lambda = nullptr;
7551  decoration.state = 0;
7552  decoration.is_present = false;
7553 
7554  xdg_decoration_map.erase(xdg_surface);
7555  }
7556 
7557  xdg_decoration = nullptr;
7558 }
7559 
7560 
7566 void Yetani::xdgDecorationChange(Yetani::XdgDecoration& decoration
7567  , const uint32_t decoration_state
7568  ) noexcept
7569 {
7570  if(decoration_state == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)
7571  {
7572  if(decoration.state != decoration_state)
7573  {
7574  decoration.state = decoration_state;
7575  decoration.is_present = false;
7576 
7577  decoration.lambda(
7578  Yetani::WindowDecorations::Client_Side
7579  );
7580  }
7581  }
7582  else if(decoration_state == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
7583  {
7584  if(decoration.state != decoration_state)
7585  {
7586  decoration.state = decoration_state;
7587  decoration.is_present = true;
7588  }
7589  else
7590  {
7591  decoration.is_present = !decoration.is_present;
7592  }
7593 
7594  if(decoration.is_present == true)
7595  {
7596  decoration.lambda(
7597  Yetani::WindowDecorations::Server_Side
7598  );
7599  }
7600  else
7601  {
7602  decoration.lambda(
7603  Yetani::WindowDecorations::Client_Side
7604  );
7605  }
7606  }
7607 }
7608 
7609 // }}}
7610 // {{{ XDG : Listener Handlers : Surface
7611 
7625 void Yetani::handlerXdgSurfaceConfigure(void* data
7626  , xdg_surface* xdg_surface
7627  , uint32_t serial
7628  ) noexcept
7629 {
7630  Yetani::XdgSurface& surface = *((Yetani::XdgSurface*)data);
7631  Yetani* yetani = surface.yetani;
7632 
7633  xdg_surface_ack_configure(xdg_surface, serial);
7634 
7635  VectorXdgStateChange& state_change = yetani->xdg_state_change_map[xdg_surface];
7636 
7637  if(state_change.empty())
7638  {
7639  return;
7640  }
7641 
7642  auto iter = std::begin(state_change);
7643  auto iter_end = std::end(state_change);
7644 
7645  while(iter != iter_end)
7646  {
7647  switch(*iter)
7648  {
7649  case Yetani::XdgState::Toplevel_Active:
7650  {
7651  Yetani::XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
7652 
7653  iter++;
7654  bool is_active = bool(*iter);
7655  if(toplevel.is_active != is_active)
7656  {
7657  toplevel.is_active = is_active;
7658 
7659  toplevel.is_active_lambda(is_active);
7660  }
7661  } break;
7662 
7663  case Yetani::XdgState::Toplevel_Attach_Buffer:
7664  {
7665  struct wl_surface* wl_surface = surface.wl_surface;
7666 
7667  SurfaceFrame& surface_frame =
7668  yetani->surface_frame_map[wl_surface];
7669 
7670  wl_surface_attach(surface_frame.wl_surface
7671  , surface_frame.buffer_next
7672  , 0, 0
7673  );
7674 
7675  struct wl_callback* callback = wl_surface_frame(surface_frame.wl_surface);
7676 
7677  wl_callback_add_listener(callback
7678  , &frame_callback_listener
7679  , &surface_frame
7680  );
7681 
7682  wl_surface_commit(surface_frame.wl_surface);
7683  } break;
7684 
7685  case Yetani::XdgState::Toplevel_Window_Normal:
7686  case Yetani::XdgState::Toplevel_Window_Maximized:
7687  case Yetani::XdgState::Toplevel_Window_Fullscreen:
7688  {
7689  struct wl_surface* wl_surface = surface.wl_surface;
7690 
7691  Yetani::XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
7692 
7693  Yetani::XdgState window_state = XdgState(*iter);
7694 
7695  Yetani::SizePixel size_pixel;
7696 
7697  iter++;
7698  size_pixel.width = *iter;
7699 
7700  iter++;
7701  size_pixel.height = *iter;
7702 
7703  if(toplevel.window_state != window_state)
7704  {
7705  xdgToplevelWindowChange(yetani
7706  , wl_surface
7707  , toplevel
7708  , window_state
7709  , size_pixel
7710  );
7711  }
7712  } break;
7713 
7714  case Yetani::XdgState::Toplevel_Resizing:
7715  {
7716  struct wl_surface* wl_surface = surface.wl_surface;
7717 
7718  Yetani::SizePixel size_pixel;
7719 
7720  iter++;
7721  size_pixel.width = *iter;
7722 
7723  iter++;
7724  size_pixel.height = *iter;
7725 
7726  if(size_pixel.width > 0
7727  && size_pixel.height > 0
7728  )
7729  {
7730  xdgToplevelSizeChange(yetani
7731  , wl_surface
7732  , size_pixel
7733  );
7734  }
7735  } break;
7736 
7737  case Yetani::XdgState::Toplevel_Decoration:
7738  {
7739  iter++;
7740  uint32_t decoration_state = *iter;
7741 
7742  Yetani::XdgDecoration& decoration = yetani->xdg_decoration_map[xdg_surface];
7743 
7744  xdgDecorationChange(decoration, decoration_state);
7745  } break;
7746  }
7747 
7748  iter++;
7749  }
7750 
7751  state_change.clear();
7752 }
7753 
7754 // }}}
7755 // {{{ XDG : Listener Handlers : Toplevel
7756 
7760 void Yetani::handlerXdgToplevelClose(void* data
7761  , struct xdg_toplevel* //xdg_toplevel ///< The toplevel surface
7762  ) noexcept
7763 {
7764  Yetani::XdgToplevel* toplevel = (Yetani::XdgToplevel*)data;
7765 
7766  toplevel->close_request_lambda();
7767 }
7768 
7769 
7773 void Yetani::handlerXdgToplevelConfigure(void* data
7774  , struct xdg_toplevel* //xdg_toplevel ///< The toplevel surface
7775  , int32_t width
7776  , int32_t height
7777  , struct wl_array* state_array
7778  ) noexcept
7779 {
7780  Yetani::XdgToplevel* toplevel = (Yetani::XdgToplevel*)data;
7781 
7782  Yetani::XdgState window_state = Yetani::XdgState::Toplevel_Window_Normal;
7783  int32_t is_active = 0;
7784 
7785  ZAKERO_YETANI__ARRAY_FOR_EACH(xdg_toplevel_state*, state_iter, state_array)
7786  {
7787  xdg_toplevel_state state = *state_iter;
7788 
7789  switch(state)
7790  {
7791  case XDG_TOPLEVEL_STATE_MAXIMIZED:
7792  window_state = Yetani::XdgState::Toplevel_Window_Maximized;
7793  break;
7794  case XDG_TOPLEVEL_STATE_FULLSCREEN:
7795  window_state = Yetani::XdgState::Toplevel_Window_Fullscreen;
7796  break;
7797  case XDG_TOPLEVEL_STATE_RESIZING:
7798  toplevel->state_change->push_back(Yetani::XdgState::Toplevel_Resizing);
7799  toplevel->state_change->push_back(width);
7800  toplevel->state_change->push_back(height);
7801  break;
7802  case XDG_TOPLEVEL_STATE_ACTIVATED:
7803  is_active = 1;
7804  break;
7805  case XDG_TOPLEVEL_STATE_TILED_LEFT:
7806  break;
7807  case XDG_TOPLEVEL_STATE_TILED_RIGHT:
7808  break;
7809  case XDG_TOPLEVEL_STATE_TILED_TOP:
7810  break;
7811  case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
7812  break;
7813  default:
7814  break;
7815  }
7816  }
7817 
7818  toplevel->state_change->push_back(window_state);
7819  toplevel->state_change->push_back(width);
7820  toplevel->state_change->push_back(height);
7821 
7822  toplevel->state_change->push_back(Yetani::XdgState::Toplevel_Active);
7823  toplevel->state_change->push_back(is_active);
7824 }
7825 
7826 // }}}
7827 // {{{ XDG : Listener Handlers : WM Base
7828 
7832 void Yetani::handlerXdgWmBasePing(void* //data ///< User data
7833  , struct xdg_wm_base* xdg_wm_base
7834  , uint32_t serial
7835  ) noexcept
7836 {
7837  xdg_wm_base_pong(xdg_wm_base, serial);
7838 }
7839 
7840 // }}}
7841 // {{{ XDG : Listener Handlers (Unstable) : Decoration
7842 
7846 void Yetani::handlerXdgToplevelDecorationConfigure(void* data
7847  , struct zxdg_toplevel_decoration_v1* //decoration ///< The Decoration object
7848  , uint32_t mode
7849  ) noexcept
7850 {
7851  Yetani::XdgDecoration* deco = (Yetani::XdgDecoration*)data;
7852 
7853  deco->state_change->push_back(Yetani::XdgState::Toplevel_Decoration);
7854  deco->state_change->push_back(mode);
7855 }
7856 
7857 // }}}
7858 // {{{ Window
7859 
7871 /* Disabled because Doxygen does not support "enum classes"
7872  *
7873  * \var Yetani::Client_Side
7874  * \brief The user app must draw the decorations.
7875  *
7876  * \var Yetani::Server_Side
7877  * \brief The Wayland Compositor will draw the decorations.
7878  */
7879 
7885 /* Disabled because Doxygen does not support "enum classes"
7886  *
7887  * \var Yetani::Normal
7888  * \brief A normal window.
7889  *
7890  * \var Yetani::Fullscreen
7891  * \brief A window that uses the entire screen, no borders.
7892  *
7893  * \var Yetani::Maximized
7894  * \brief A window that uses as much of the screen as possible.
7895  */
7896 
7897 
8025  , std::error_code& error
8026  ) noexcept
8027 {
8028  return windowCreate(Yetani::SizeUnit::Millimeter
8029  , size
8030  , { 0, 0 }
8031  , { 0, 0 }
8032  , SHM_FORMAT_DEFAULT
8033  , error
8034  );
8035 }
8036 
8037 
8051  , const wl_shm_format format
8052  ) noexcept
8053 {
8054  std::error_code error;
8055 
8056  return windowCreate(Yetani::SizeUnit::Millimeter
8057  , size
8058  , { 0, 0 }
8059  , { 0, 0 }
8060  , format
8061  , error
8062  );
8063 }
8064 
8065 
8082  , const wl_shm_format format
8083  , std::error_code& error
8084  ) noexcept
8085 {
8086  return windowCreate(Yetani::SizeUnit::Millimeter
8087  , size
8088  , { 0, 0 }
8089  , { 0, 0 }
8090  , format
8091  , error
8092  );
8093 }
8094 
8095 
8110  , std::error_code& error
8111  ) noexcept
8112 {
8113  return windowCreate(Yetani::SizeUnit::Percent
8114  , { 0, 0 }
8115  , size
8116  , { 0, 0 }
8117  , SHM_FORMAT_DEFAULT
8118  , error
8119  );
8120 }
8121 
8122 
8136  , const wl_shm_format format
8137  ) noexcept
8138 {
8139  std::error_code error;
8140 
8141  return windowCreate(Yetani::SizeUnit::Percent
8142  , { 0, 0 }
8143  , size
8144  , { 0, 0 }
8145  , format
8146  , error
8147  );
8148 }
8149 
8150 
8167  , const wl_shm_format format
8168  , std::error_code& error
8169  ) noexcept
8170 {
8171  return windowCreate(Yetani::SizeUnit::Percent
8172  , { 0, 0 }
8173  , size
8174  , { 0, 0 }
8175  , format
8176  , error
8177  );
8178 }
8179 
8180 
8195  , std::error_code& error
8196  ) noexcept
8197 {
8198  return windowCreate(Yetani::SizeUnit::Pixel
8199  , { 0, 0 }
8200  , { 0, 0 }
8201  , size
8202  , SHM_FORMAT_DEFAULT
8203  , error
8204  );
8205 }
8206 
8207 
8221  , const wl_shm_format format
8222  ) noexcept
8223 {
8224  std::error_code error;
8225 
8226  return windowCreate(Yetani::SizeUnit::Pixel
8227  , { 0, 0 }
8228  , { 0, 0 }
8229  , size
8230  , format
8231  , error
8232  );
8233 }
8234 
8235 
8252  , const wl_shm_format format
8253  , std::error_code& error
8254  ) noexcept
8255 {
8256  return windowCreate(Yetani::SizeUnit::Pixel
8257  , { 0, 0 }
8258  , { 0, 0 }
8259  , size
8260  , format
8261  , error
8262  );
8263 }
8264 
8265 
8273 Yetani::Window* Yetani::windowCreate(const Yetani::SizeUnit size_unit
8274  , const Yetani::SizeMm& size_mm
8275  , const Yetani::SizePercent& size_percent
8276  , const Yetani::SizePixel& size_pixel
8277  , const wl_shm_format pixel_format
8278  , std::error_code& error
8279  ) noexcept
8280 {
8281  if((size_unit == Yetani::SizeUnit::Millimeter)
8282  && (size_mm.width <= 0 || size_mm.height <= 0)
8283  )
8284  {
8285  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8286 
8287  return nullptr;
8288  }
8289 
8290  if((size_unit == Yetani::SizeUnit::Percent)
8291  && (size_percent.width <= 0 || size_percent.height <= 0)
8292  )
8293  {
8294  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8295 
8296  return nullptr;
8297  }
8298 
8299  if((size_unit == Yetani::SizeUnit::Pixel)
8300  && (size_pixel.width <= 0 || size_pixel.height <= 0)
8301  )
8302  {
8303  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8304 
8305  return nullptr;
8306  }
8307 
8308  const std::string file_name = "Zakero.Yetani."
8309  + std::to_string(ZAKERO_STEADY_TIME_NOW(nanoseconds))
8310  ;
8311 
8312  struct WindowData window_data =
8313  { .yetani = this
8314  , .wl_shm = shm
8315  , .wl_output = nullptr
8316  , .file_name = file_name
8317  , .size_mm = size_mm
8318  , .size_percent = size_percent
8319  , .size_pixel = size_pixel
8320  , .size_unit = size_unit
8321  , .pixel_format = pixel_format
8322  , .error = ZAKERO_YETANI__ERROR(Error_None)
8323  };
8324 
8325  windowDataInit(window_data);
8326 
8327  if(window_data.error)
8328  {
8329  error = window_data.error;
8330 
8331  return nullptr;
8332  }
8333 
8334  Yetani::Window* window = new Window(&window_data);
8335 
8336  if(window_data.error)
8337  {
8338  delete window;
8339  window = nullptr;
8340 
8341  ZAKERO_YETANI__DEBUG << to_string(window_data.error) << "\n";
8342 
8343  error = ZAKERO_YETANI__ERROR(Error_Window_Initialization_Failed);
8344 
8345  return nullptr;
8346  }
8347 
8348  error = ZAKERO_YETANI__ERROR(Error_None);
8349 
8350  return window;
8351 }
8352 
8353 
8357 void Yetani::windowDataInit(Yetani::WindowData& window_data
8358  ) noexcept
8359 {
8360  windowDataInitOutput(window_data);
8361 
8362  if(window_data.error)
8363  {
8364  return;
8365  }
8366 
8367  window_data.size_pixel.width = std::max(1, window_data.size_pixel.width);
8368  window_data.size_pixel.height = std::max(1, window_data.size_pixel.height);
8369 
8370  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8371 }
8372 
8373 
8377 void Yetani::windowDataInitOutput(Yetani::WindowData& window_data
8378  ) noexcept
8379 {
8380  std::lock_guard<std::mutex> lock(output_data.mutex);
8381 
8382  if(output_data.output_map.empty())
8383  {
8384  window_data.error = ZAKERO_YETANI__ERROR(Error_No_Output_Available);
8385 
8386  return;
8387  }
8388 
8389  const auto& iter = output_data.output_map.begin();
8390 
8391  window_data.wl_output = iter->first;
8392  Yetani::Output& output = iter->second;
8393 
8394  if(window_data.size_unit == Yetani::SizeUnit::Millimeter)
8395  {
8396  auto px = convertMmToPixel(output
8397  , window_data.size_mm.width
8398  , window_data.size_mm.height
8399  );
8400 
8401  auto pc = convertPixelToPercent(output
8402  , px.first
8403  , px.second
8404  );
8405 
8406  window_data.size_mm = window_data.size_mm;
8407  window_data.size_percent = { pc.first, pc.second };
8408  window_data.size_pixel = { px.first, px.second };
8409  }
8410  else if(window_data.size_unit == Yetani::SizeUnit::Percent)
8411  {
8412  auto px = convertPercentToPixel(output
8413  , window_data.size_percent.width
8414  , window_data.size_percent.height
8415  );
8416 
8417  auto mm = convertPixelToMm(output
8418  , px.first
8419  , px.second
8420  );
8421 
8422  window_data.size_mm = { mm.first, mm.second };
8423  window_data.size_percent = window_data.size_percent;
8424  window_data.size_pixel = { px.first, px.second };
8425  }
8426  else if(window_data.size_unit == Yetani::SizeUnit::Pixel)
8427  {
8428  auto mm = convertPixelToMm(output
8429  , window_data.size_pixel.width
8430  , window_data.size_pixel.height
8431  );
8432 
8433  auto pc = convertPixelToPercent(output
8434  , window_data.size_pixel.width
8435  , window_data.size_pixel.height
8436  );
8437 
8438  window_data.size_mm = { mm.first, mm.second };
8439  window_data.size_percent = { pc.first, pc.second };
8440  window_data.size_pixel = window_data.size_pixel;
8441  }
8442 
8443  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8444 }
8445 
8446 
8450 void Yetani::windowInitMemory(Yetani::WindowData& window_data
8451  , Yetani::Window::Memory& window_memory
8452  ) noexcept
8453 {
8454  size_t size_in_bytes = sizeInBytes(window_data.size_pixel
8455  , window_data.pixel_format
8456  ) * 3;
8457 
8458  window_data.error = window_memory.memory_pool.init(size_in_bytes
8459  , true
8460  , zakero::MemoryPool::Alignment::Bits_32
8461  );
8462 
8463  if(window_data.error)
8464  {
8465  return;
8466  }
8467 
8468  window_memory.wl_shm_pool = wl_shm_create_pool(window_data.wl_shm
8469  , window_memory.memory_pool.fd()
8470  , window_memory.memory_pool.size()
8471  );
8472 
8473  window_memory.memory_pool.sizeOnChange([&](size_t new_size)
8474  {
8475  wl_shm_pool_resize(window_memory.wl_shm_pool, new_size);
8476  });
8477 
8478  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8479 }
8480 
8481 
8485 void Yetani::windowInitOutput(Yetani::WindowData& window_data
8486  , struct wl_surface* wl_surface
8487  ) noexcept
8488 {
8489  std::lock_guard<std::mutex> lock(output_data.mutex);
8490 
8491  output_data.surface_output_map[wl_surface].push_back(window_data.wl_output);
8492 }
8493 
8494 
8498 void Yetani::windowEraseMemory(Yetani::Window::Memory& window_memory
8499  ) noexcept
8500 {
8501  if(window_memory.wl_shm_pool)
8502  {
8503  wl_shm_pool_destroy(window_memory.wl_shm_pool);
8504  window_memory.wl_shm_pool = nullptr;
8505  }
8506 }
8507 
8508 
8512 void Yetani::windowEraseOutput(struct wl_surface* wl_surface
8513  ) noexcept
8514 {
8515  std::lock_guard<std::mutex> lock(output_data.mutex);
8516 
8517  if(output_data.surface_output_map.contains(wl_surface))
8518  {
8519  output_data.surface_output_map.erase(wl_surface);
8520  }
8521 }
8522 
8523 
8527 void Yetani::windowEraseSurfaceExtent(struct wl_surface* wl_surface
8528  ) noexcept
8529 {
8530  std::lock_guard<std::mutex> lock(surface_extent_mutex);
8531 
8532  if(surface_extent_map.contains(wl_surface))
8533  {
8534  surface_extent_map.erase(wl_surface);
8535  }
8536 }
8537 
8538 
8542 void Yetani::windowAdd(Yetani::Window* window
8543  ) noexcept
8544 {
8545  std::lock_guard<std::mutex> lock(window_vector_mutex);
8546 
8547  window_vector.push_back(window);
8548 }
8549 
8550 
8554 void Yetani::windowRemove(Yetani::Window* window
8555  ) noexcept
8556 {
8557  std::lock_guard<std::mutex> lock(window_vector_mutex);
8558 
8559  zakero::vectorErase(window_vector, window);
8560 }
8561 
8562 // }}}
8563 // {{{ Window : Documentation
8564 
8730 // }}}
8731 // {{{ Window : Constructor / Destructor
8732 
8761  )
8762  : yetani {((Yetani::WindowData*)ptr)->yetani}
8763  , wl_buffer {nullptr}
8764  , wl_surface {nullptr}
8765  , xdg_surface {nullptr}
8766  , xdg_toplevel {nullptr}
8767  , xdg_decoration {nullptr}
8768  , window_memory {nullptr, ((Yetani::WindowData*)ptr)->file_name}
8769  , pixel_format {((Yetani::WindowData*)ptr)->pixel_format}
8770 {
8771  Yetani::WindowData& window_data = *((Yetani::WindowData*)ptr);
8772 
8773  yetani->windowInitMemory(window_data, window_memory);
8774  if(window_data.error)
8775  {
8776  return;
8777  }
8778 
8779  wl_surface = yetani->surfaceCreate(yetani
8780  , pixel_format
8781  , window_data.size_pixel
8782  , window_memory
8783  );
8784 
8785  xdg_surface = yetani->xdgSurfaceCreate(wl_surface);
8786 
8787  yetani->xdgSurfaceSetExtent(wl_surface
8788  , window_data.size_unit
8789  , window_data.size_mm
8790  , window_data.size_percent
8791  , window_data.size_pixel
8792  );
8793 
8794  xdg_toplevel = yetani->xdgToplevelCreate(xdg_surface);
8795 
8796  xdg_decoration = yetani->xdgDecorationCreate(xdg_surface, xdg_toplevel);
8797 
8798  wl_surface_commit(wl_surface);
8799 
8800  yetani->windowInitOutput(window_data, wl_surface);
8801  if(window_data.error)
8802  {
8803  return;
8804  }
8805 
8806  yetani->windowAdd(this);
8807 }
8808 
8809 
8814 {
8815  yetani->windowRemove(this);
8816 
8817  if(xdg_decoration != nullptr)
8818  {
8819  yetani->xdgDecorationDestroy(xdg_surface, xdg_toplevel, xdg_decoration);
8820  }
8821 
8822  if(xdg_toplevel != nullptr)
8823  {
8824  yetani->xdgToplevelDestroy(xdg_surface, xdg_toplevel);
8825  }
8826 
8827  if(xdg_surface != nullptr)
8828  {
8829  yetani->xdgSurfaceDestroy(wl_surface, xdg_surface);
8830  }
8831 
8832  if(wl_surface != nullptr)
8833  {
8834  yetani->windowEraseOutput(wl_surface);
8835  yetani->surfaceDestroy(yetani, wl_surface);
8836  yetani->windowEraseSurfaceExtent(wl_surface);
8837  }
8838 
8839  yetani->windowEraseMemory(window_memory);
8840 }
8841 
8842 // }}}
8843 // {{{ Window : Cursor
8844 
8858 std::error_code Yetani::Window::cursorUse(const std::string& name
8859  ) noexcept
8860 {
8861  if(name.empty())
8862  {
8863  return yetani->cursorDetach(wl_surface);
8864  }
8865 
8866  return yetani->cursorAttach(name, wl_surface);
8867 }
8868 
8869 
8876 {
8877  yetani->cursorHide(wl_surface);
8878 }
8879 
8880 
8887 {
8888  yetani->cursorShow(wl_surface);
8889 }
8890 
8891 // }}}
8892 // {{{ Window : Settings
8893 
8910 void Yetani::Window::classSet(const std::string& class_name
8911  ) noexcept
8912 {
8913  xdg_toplevel_set_app_id(xdg_toplevel, class_name.c_str());
8914 }
8915 
8916 
8923 void Yetani::Window::titleSet(const std::string& title
8924  ) noexcept
8925 {
8926  xdg_toplevel_set_title(xdg_toplevel, title.c_str());
8927 }
8928 
8929 
8950  ) noexcept
8951 {
8952  if(yetani->decoration_manager == nullptr)
8953  {
8954  return ZAKERO_YETANI__ERROR(Error_Server_Side_Decorations_Not_Available);
8955  }
8956 
8957  uint32_t decoration_state = decorations == Yetani::WindowDecorations::Server_Side
8958  ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
8959  : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE
8960  ;
8961 
8962  zxdg_toplevel_decoration_v1_set_mode(xdg_decoration
8963  , decoration_state
8964  );
8965 
8966  return ZAKERO_YETANI__ERROR(Error_None);
8967 }
8968 
8969 
8978 {
8979  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
8980 
8981  Yetani::WindowMode window_mode = Yetani::toWindowMode(toplevel.window_state);
8982 
8983  return window_mode;
8984 }
8985 
8986 
8996  ) noexcept
8997 {
8998  XdgState window_state = Yetani::toXdgState(window_mode);
8999 
9000  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9001 
9002  if(toplevel.window_state == window_state)
9003  {
9004  return true;
9005  }
9006 
9007  return false;
9008 }
9009 
9010 
9020  ) noexcept
9021 {
9022  XdgState window_state = Yetani::toXdgState(window_mode);
9023 
9024  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9025 
9026  if(toplevel.window_state == window_state)
9027  {
9028  return;
9029  }
9030 
9031  switch(window_mode)
9032  {
9033  case WindowMode::Fullscreen:
9034  xdg_toplevel_set_fullscreen(xdg_toplevel, nullptr);
9035  break;
9036 
9037  case WindowMode::Maximized:
9038  xdg_toplevel_set_maximized(xdg_toplevel);
9039  break;
9040 
9041  case WindowMode::Normal:
9042  xdg_toplevel_unset_fullscreen(xdg_toplevel);
9043  xdg_toplevel_unset_maximized(xdg_toplevel);
9044  break;
9045  }
9046 }
9047 
9048 
9065 std::error_code Yetani::Window::sizeSet(const Yetani::SizeMm& size
9066  ) noexcept
9067 {
9068  if(size.width <= 0 || size.height <= 0)
9069  {
9070  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9071  }
9072 
9073  Yetani::SizePixel size_pixel = convertToPixel(size);
9074 
9075  if(size_pixel.width <= 0)
9076  {
9077  size_pixel.width = 1;
9078  }
9079 
9080  if(size_pixel.height <= 0)
9081  {
9082  size_pixel.height = 1;
9083  }
9084 
9085  yetani->surface_resize_mutex_map[wl_surface].lock();
9086  {
9087  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9088 
9089  surface_extent.preferred_unit = Yetani::SizeUnit::Millimeter;
9090  surface_extent.preferred_mm = size;
9091  surface_extent.size_pixel = size_pixel;
9092 
9093  surfaceCalculateSize(yetani, wl_surface, size_pixel);
9094  }
9095  yetani->surface_resize_mutex_map[wl_surface].unlock();
9096 
9097  return ZAKERO_YETANI__ERROR(Error_None);
9098 }
9099 
9100 
9117 std::error_code Yetani::Window::sizeSet(const Yetani::SizePercent& size
9118  ) noexcept
9119 {
9120  if(size.width <= 0 || size.height <= 0)
9121  {
9122  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9123  }
9124 
9125  Yetani::SizePixel size_pixel = convertToPixel(size);
9126 
9127  if(size_pixel.width <= 0)
9128  {
9129  size_pixel.width = 1;
9130  }
9131 
9132  if(size_pixel.height <= 0)
9133  {
9134  size_pixel.height = 1;
9135  }
9136 
9137  yetani->surface_resize_mutex_map[wl_surface].lock();
9138  {
9139  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9140 
9141  surface_extent.preferred_unit = Yetani::SizeUnit::Percent;
9142  surface_extent.preferred_percent = size;
9143  surface_extent.size_pixel = size_pixel;
9144 
9145  surfaceCalculateSize(yetani, wl_surface, size_pixel);
9146  }
9147  yetani->surface_resize_mutex_map[wl_surface].unlock();
9148 
9149  return ZAKERO_YETANI__ERROR(Error_None);
9150 }
9151 
9152 
9169 std::error_code Yetani::Window::sizeSet(const Yetani::SizePixel& size
9170  ) noexcept
9171 {
9172  if(size.width <= 0 || size.height <= 0)
9173  {
9174  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9175  }
9176 
9177  yetani->surface_resize_mutex_map[wl_surface].lock();
9178  {
9179  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9180 
9181  surface_extent.preferred_unit = Yetani::SizeUnit::Pixel;
9182  surface_extent.size_pixel = size;
9183 
9184  surfaceCalculateSize(yetani, wl_surface, size);
9185  }
9186  yetani->surface_resize_mutex_map[wl_surface].unlock();
9187 
9188  return ZAKERO_YETANI__ERROR(Error_None);
9189 }
9190 
9191 
9203 std::error_code Yetani::Window::sizeSetMinMax(const Yetani::SizeMm& size_min
9204  , const Yetani::SizeMm& size_max
9205  ) noexcept
9206 {
9207  std::error_code error = validateMinMax<Yetani::SizeMm>(size_min, size_max);
9208  if(error)
9209  {
9210  return error;
9211  }
9212 
9213  Yetani::SizePixel size_pixel_min;
9214  Yetani::SizePixel size_pixel_max;
9215 
9216  {
9217  Yetani::OutputData& output_data = yetani->output_data;
9218 
9219  std::lock_guard<std::mutex> lock(output_data.mutex);
9220 
9221  Yetani::VectorWlOutput& vector = output_data.surface_output_map[wl_surface];
9222  struct wl_output* wl_output = vector.front();
9223  const Yetani::Output& output = output_data.output_map[wl_output];
9224 
9225  auto min = yetani->convertMmToPixel(output, size_min.width, size_min.height);
9226  size_pixel_min = { min.first, min.second };
9227 
9228  auto max = yetani->convertMmToPixel(output, size_max.width, size_max.height);
9229  size_pixel_max = { max.first, max.second };
9230  }
9231 
9232  yetani->xdgToplevelSizeMinMaxChange(yetani
9233  , xdg_toplevel
9234  , wl_surface
9235  , size_pixel_min
9236  , size_pixel_max
9237  );
9238 
9239  return ZAKERO_YETANI__ERROR(Error_None);
9240 }
9241 
9242 
9254 std::error_code Yetani::Window::sizeSetMinMax(const Yetani::SizePercent& size_min
9255  , const Yetani::SizePercent& size_max
9256  ) noexcept
9257 {
9258  std::error_code error = validateMinMax<Yetani::SizePercent>(size_min, size_max);
9259  if(error)
9260  {
9261  return error;
9262  }
9263 
9264  Yetani::SizePixel size_pixel_min;
9265  Yetani::SizePixel size_pixel_max;
9266 
9267  {
9268  Yetani::OutputData& output_data = yetani->output_data;
9269 
9270  std::lock_guard<std::mutex> lock(output_data.mutex);
9271 
9272  Yetani::VectorWlOutput& vector = output_data.surface_output_map[wl_surface];
9273  struct wl_output* wl_output = vector.front();
9274  const Yetani::Output& output = output_data.output_map[wl_output];
9275 
9276  auto min = yetani->convertPercentToPixel(output, size_min.width, size_min.height);
9277  size_pixel_min = { min.first, min.second };
9278 
9279  auto max = yetani->convertPercentToPixel(output, size_max.width, size_max.height);
9280  size_pixel_max = { max.first, max.second };
9281  }
9282 
9283  yetani->xdgToplevelSizeMinMaxChange(yetani
9284  , xdg_toplevel
9285  , wl_surface
9286  , size_pixel_min
9287  , size_pixel_max
9288  );
9289 
9290  return ZAKERO_YETANI__ERROR(Error_None);
9291 }
9292 
9293 
9305 std::error_code Yetani::Window::sizeSetMinMax(const Yetani::SizePixel& size_min
9306  , const Yetani::SizePixel& size_max
9307  ) noexcept
9308 {
9309  std::error_code error = validateMinMax<Yetani::SizePixel>(size_min, size_max);
9310  if(error)
9311  {
9312  return error;
9313  }
9314 
9315  yetani->xdgToplevelSizeMinMaxChange(yetani
9316  , xdg_toplevel
9317  , wl_surface
9318  , size_min
9319  , size_max
9320  );
9321 
9322  return ZAKERO_YETANI__ERROR(Error_None);
9323 }
9324 
9325 // }}}
9326 // {{{ Window : Rendering
9327 
9364 std::error_code Yetani::Window::imageNext(uint8_t*& image
9365  , Yetani::SizePixel& size
9366  ) noexcept
9367 {
9368  if(wl_buffer != nullptr)
9369  {
9370  bufferDestroy(wl_buffer);
9371  }
9372 
9373  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
9374 
9375  yetani->surface_resize_mutex_map[wl_surface].lock();
9376  {
9377  wl_buffer = bufferCreate(surface_size
9378  , &window_memory
9379  , &yetani->buffer
9380  );
9381  }
9382  yetani->surface_resize_mutex_map[wl_surface].unlock();
9383 
9384  image = window_memory.memory_pool.addressOf(
9385  yetani->buffer.map[wl_buffer].offset
9386  );
9387 
9388  size = { surface_size.width, surface_size.height };
9389 
9390  return ZAKERO_YETANI__ERROR(Error_None);
9391 }
9392 
9393 
9401 {
9402  if(wl_buffer == nullptr)
9403  {
9404  // This nullptr check is needed because:
9405  // - If imagePresent() is called before imageNext() then
9406  // wl_buffer could be nullptr.
9407  // - There is a chance that a valid "buffer_next" can be
9408  // replaced with a nullptr, and this will cause a
9409  // frame-drop.
9410 
9411  return;
9412  }
9413 
9414  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
9415 
9416  wl_buffer = surface_frame.buffer_next.exchange(wl_buffer);
9417 }
9418 
9419 
9432 uint32_t Yetani::Window::time() const noexcept
9433 {
9434  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
9435 
9436  return surface_frame.time_ms;
9437 }
9438 
9439 // }}}
9440 // {{{ Window : Misc
9441 
9450 uint8_t Yetani::Window::bytesPerPixel() const noexcept
9451 {
9452  return yetani->shmFormatBytesPerPixel(pixel_format);
9453 }
9454 
9455 
9464 {
9465  xdg_toplevel_set_minimized(xdg_toplevel);
9466 }
9467 
9468 // }}}
9469 // {{{ Window : Measurement Conversion
9470 
9479  ) const noexcept
9480 {
9481  const Yetani::OutputData& output_data = yetani->output_data;
9482 
9483  std::lock_guard<std::mutex> lock(output_data.mutex);
9484 
9485  struct wl_output* wl_output = output_data.surface_output_map.at(wl_surface).front();
9486  const Yetani::Output& output = output_data.output_map.at(wl_output);
9487 
9488  auto p = yetani->convertPixelToMm(output, point.x, point.y);
9489 
9490  return { point.time, p.first, p.second };
9491 }
9492 
9493 
9502  ) const noexcept
9503 {
9504  const Yetani::OutputData& output_data = yetani->output_data;
9505 
9506  std::lock_guard<std::mutex> lock(output_data.mutex);
9507 
9508  struct wl_output* wl_output = output_data.surface_output_map.at(wl_surface).front();
9509  const Yetani::Output& output = output_data.output_map.at(wl_output);
9510 
9511  auto p = yetani->convertPixelToPercent(output, point.x, point.y);
9512 
9513  return { point.time, p.first, p.second };
9514 }
9515 
9516 
9525  ) const noexcept
9526 {
9527  Yetani::OutputData& output_data = yetani->output_data;
9528 
9529  std::lock_guard<std::mutex> lock(output_data.mutex);
9530 
9531  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9532  const Yetani::Output& output = output_data.output_map[wl_output];
9533 
9534  auto p = yetani->convertMmToPixel(output, point.x, point.y);
9535 
9536  return { point.time, p.first, p.second };
9537 }
9538 
9539 
9548  ) const noexcept
9549 {
9550  Yetani::OutputData& output_data = yetani->output_data;
9551 
9552  std::lock_guard<std::mutex> lock(output_data.mutex);
9553 
9554  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9555  const Yetani::Output& output = output_data.output_map[wl_output];
9556 
9557  auto p = yetani->convertPercentToPixel(output, point.x, point.y);
9558 
9559  return { point.time, p.first, p.second };
9560 }
9561 
9562 
9571  ) const noexcept
9572 {
9573  Yetani::OutputData& output_data = yetani->output_data;
9574 
9575  std::lock_guard<std::mutex> lock(output_data.mutex);
9576 
9577  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9578  const Yetani::Output& output = output_data.output_map[wl_output];
9579 
9580  auto p = yetani->convertPixelToMm(output, size.width, size.height);
9581 
9582  return { p.first, p.second };
9583 }
9584 
9585 
9594  ) const noexcept
9595 {
9596  Yetani::OutputData& output_data = yetani->output_data;
9597 
9598  std::lock_guard<std::mutex> lock(output_data.mutex);
9599 
9600  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9601  const Yetani::Output& output = output_data.output_map[wl_output];
9602 
9603  auto p = yetani->convertPixelToPercent(output, size.width, size.height);
9604 
9605  return { p.first, p.second };
9606 }
9607 
9608 
9617  ) const noexcept
9618 {
9619  Yetani::OutputData& output_data = yetani->output_data;
9620 
9621  std::lock_guard<std::mutex> lock(output_data.mutex);
9622 
9623  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9624  const Yetani::Output& output = output_data.output_map[wl_output];
9625 
9626  auto p = yetani->convertMmToPixel(output, size.width, size.height);
9627 
9628  return { p.first, p.second };
9629 }
9630 
9631 
9640  ) const noexcept
9641 {
9642  Yetani::OutputData& output_data = yetani->output_data;
9643 
9644  std::lock_guard<std::mutex> lock(output_data.mutex);
9645 
9646  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9647  const Yetani::Output& output = output_data.output_map[wl_output];
9648 
9649  auto p = yetani->convertPercentToPixel(output, size.width, size.height);
9650 
9651  return { p.first, p.second };
9652 }
9653 
9654 // }}}
9655 // {{{ Window : Event Handling
9656 
9669  ) noexcept
9670 {
9671  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9672 
9673  if(lambda == nullptr)
9674  {
9675  toplevel.close_request_lambda = Lambda_DoNothing;
9676  }
9677  else
9678  {
9679  toplevel.close_request_lambda = lambda;
9680  }
9681 }
9682 
9683 
9694  ) noexcept
9695 {
9696  XdgDecoration& decoration = yetani->xdg_decoration_map[xdg_surface];
9697 
9698  if(lambda == nullptr)
9699  {
9700  decoration.lambda = LambdaWindowDecorations_DoNothing;
9701  }
9702  else
9703  {
9704  decoration.lambda = lambda;
9705  }
9706 }
9707 
9708 
9723  ) noexcept
9724 {
9725  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9726 
9727  if(lambda == nullptr)
9728  {
9729  toplevel.is_active_lambda = LambdaBool_DoNothing;
9730  }
9731  else
9732  {
9733  toplevel.is_active_lambda = lambda;
9734  }
9735 }
9736 
9737 
9744  ) noexcept
9745 {
9746  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9747  {
9748  return;
9749  }
9750 
9751  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9752 
9753  if(lambda == nullptr)
9754  {
9755  event.on_enter = Lambda_DoNothing;
9756  }
9757  else
9758  {
9759  event.on_enter = lambda;
9760  }
9761 }
9762 
9763 
9770  ) noexcept
9771 {
9772  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9773  {
9774  return;
9775  }
9776 
9777  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9778 
9779  if(lambda == nullptr)
9780  {
9781  event.on_leave = Lambda_DoNothing;
9782  }
9783  else
9784  {
9785  event.on_leave = lambda;
9786  }
9787 }
9788 
9789 
9798  ) noexcept
9799 {
9800  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9801  {
9802  return;
9803  }
9804 
9805  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9806 
9807  if(lambda == nullptr)
9808  {
9809  event.on_key = LambdaKey_DoNothing;
9810  }
9811  else
9812  {
9813  event.on_key = lambda;
9814  }
9815 }
9816 
9817 
9825  ) noexcept
9826 {
9827  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9828 
9829  if(lambda == nullptr)
9830  {
9831  toplevel.window_state_lambda = LambdaWindowMode_DoNothing;
9832  }
9833  else
9834  {
9835  toplevel.window_state_lambda = lambda;
9836  }
9837 }
9838 
9839 
9854  ) noexcept
9855 {
9856  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9857 
9858  if(lambda == nullptr)
9859  {
9860  event.on_size_mm_change = LambdaSizeMm_DoNothing;
9861  }
9862  else
9863  {
9864  event.on_size_mm_change = lambda;
9865  }
9866 }
9867 
9868 
9883  ) noexcept
9884 {
9885  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9886 
9887  if(lambda == nullptr)
9888  {
9889  event.on_size_percent_change = LambdaSizePercent_DoNothing;
9890  }
9891  else
9892  {
9893  event.on_size_percent_change = lambda;
9894  }
9895 }
9896 
9897 
9912  ) noexcept
9913 {
9914  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9915 
9916  if(lambda == nullptr)
9917  {
9918  event.on_size_pixel_change = LambdaSizePixel_DoNothing;
9919  }
9920  else
9921  {
9922  event.on_size_pixel_change = lambda;
9923  }
9924 }
9925 
9926 
9935  ) noexcept
9936 {
9937  if(yetani->pointer.event_map.contains(wl_surface) == false)
9938  {
9939  return;
9940  }
9941 
9942  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9943 
9944  if(lambda == nullptr)
9945  {
9946  event.on_button_mm = LambdaButtonMm_DoNothing;
9947  }
9948  else
9949  {
9950  event.on_button_mm = lambda;
9951  }
9952 }
9953 
9954 
9963  ) noexcept
9964 {
9965  if(yetani->pointer.event_map.contains(wl_surface) == false)
9966  {
9967  return;
9968  }
9969 
9970  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9971 
9972  if(lambda == nullptr)
9973  {
9974  event.on_button_percent = LambdaButtonPercent_DoNothing;
9975  }
9976  else
9977  {
9978  event.on_button_percent = lambda;
9979  }
9980 }
9981 
9982 
9991  ) noexcept
9992 {
9993  if(yetani->pointer.event_map.contains(wl_surface) == false)
9994  {
9995  return;
9996  }
9997 
9998  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9999 
10000  if(lambda == nullptr)
10001  {
10002  event.on_button_pixel = LambdaButtonPixel_DoNothing;
10003  }
10004  else
10005  {
10006  event.on_button_pixel = lambda;
10007  }
10008 }
10009 
10010 
10022  ) noexcept
10023 {
10024  if(yetani->pointer.event_map.contains(wl_surface) == false)
10025  {
10026  return;
10027  }
10028 
10029  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10030 
10031  if(lambda == nullptr)
10032  {
10033  event.on_enter_mm = LambdaPointMm_DoNothing;
10034  }
10035  else
10036  {
10037  event.on_enter_mm = lambda;
10038  }
10039 }
10040 
10041 
10053  ) noexcept
10054 {
10055  if(yetani->pointer.event_map.contains(wl_surface) == false)
10056  {
10057  return;
10058  }
10059 
10060  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10061 
10062  if(lambda == nullptr)
10063  {
10064  event.on_enter_percent = LambdaPointPercent_DoNothing;
10065  }
10066  else
10067  {
10068  event.on_enter_percent = lambda;
10069  }
10070 }
10071 
10072 
10084  ) noexcept
10085 {
10086  if(yetani->pointer.event_map.contains(wl_surface) == false)
10087  {
10088  return;
10089  }
10090 
10091  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10092 
10093  if(lambda == nullptr)
10094  {
10095  event.on_enter_pixel = LambdaPointPixel_DoNothing;
10096  }
10097  else
10098  {
10099  event.on_enter_pixel = lambda;
10100  }
10101 }
10102 
10103 
10112  ) noexcept
10113 {
10114  if(yetani->pointer.event_map.contains(wl_surface) == false)
10115  {
10116  return;
10117  }
10118 
10119  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10120 
10121  if(lambda == nullptr)
10122  {
10123  event.on_leave = Lambda_DoNothing;
10124  }
10125  else
10126  {
10127  event.on_leave = lambda;
10128  }
10129 }
10130 
10131 
10140  ) noexcept
10141 {
10142  if(yetani->pointer.event_map.contains(wl_surface) == false)
10143  {
10144  return;
10145  }
10146 
10147  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10148 
10149  if(lambda == nullptr)
10150  {
10151  event.on_motion_mm = LambdaPointMm_DoNothing;
10152  }
10153  else
10154  {
10155  event.on_motion_mm = lambda;
10156  }
10157 }
10158 
10159 
10168  ) noexcept
10169 {
10170  if(yetani->pointer.event_map.contains(wl_surface) == false)
10171  {
10172  return;
10173  }
10174 
10175  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10176 
10177  if(lambda == nullptr)
10178  {
10179  event.on_motion_percent = LambdaPointPercent_DoNothing;
10180  }
10181  else
10182  {
10183  event.on_motion_percent = lambda;
10184  }
10185 }
10186 
10187 
10196  ) noexcept
10197 {
10198  if(yetani->pointer.event_map.contains(wl_surface) == false)
10199  {
10200  return;
10201  }
10202 
10203  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10204 
10205  if(lambda == nullptr)
10206  {
10207  event.on_motion_pixel = LambdaPointPixel_DoNothing;
10208  }
10209  else
10210  {
10211  event.on_motion_pixel = lambda;
10212  }
10213 }
10214 
10215 
10223  ) noexcept
10224 {
10225  if(yetani->pointer.event_map.contains(wl_surface) == false)
10226  {
10227  return;
10228  }
10229 
10230  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10231 
10232  if(lambda == nullptr)
10233  {
10234  event.on_axis = LambdaAxis_DoNothing;
10235  }
10236  else
10237  {
10238  event.on_axis = lambda;
10239  }
10240 }
10241 
10242 
10250  ) noexcept
10251 {
10252  if(yetani->pointer.event_map.contains(wl_surface) == false)
10253  {
10254  return;
10255  }
10256 
10257  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10258 
10259  if(lambda == nullptr)
10260  {
10261  event.on_axis_source = Lambda_DoNothing;
10262  }
10263  else
10264  {
10265  event.on_axis_source = lambda;
10266  }
10267 }
10268 
10269 
10277  ) noexcept
10278 {
10279  if(yetani->pointer.event_map.contains(wl_surface) == false)
10280  {
10281  return;
10282  }
10283 
10284  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10285 
10286  if(lambda == nullptr)
10287  {
10288  event.on_axis_stop = Lambda_DoNothing;
10289  }
10290  else
10291  {
10292  event.on_axis_stop = lambda;
10293  }
10294 }
10295 
10296 
10304  ) noexcept
10305 {
10306  if(yetani->pointer.event_map.contains(wl_surface) == false)
10307  {
10308  return;
10309  }
10310 
10311  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10312 
10313  if(lambda == nullptr)
10314  {
10315  event.on_axis_discrete = Lambda_DoNothing;
10316  }
10317  else
10318  {
10319  event.on_axis_discrete = lambda;
10320  }
10321 }
10322 
10323 // }}}
10324 // {{{ Window : Helpers
10325 
10326 
10327 // }}}
10328 // {{{ Convenience
10329 
10337 std::string to_string(const wl_shm_format& shm_format
10338  ) noexcept
10339 {
10340  return Yetani::shmFormatName(shm_format);
10341 }
10342 
10343 
10351 std::string to_string(const Yetani::Key& key
10352  ) noexcept
10353 {
10354  return std::string()
10355  + "{ \"time\": " + std::to_string(key.time)
10356  + ", \"code\": " + std::to_string(key.code)
10357  + ", \"state\": \"" + zakero::to_string(key.state) + "\""
10358  + " }";
10359 }
10360 
10361 
10370 std::string to_string(const Yetani::KeyModifier& key_modifier
10371  ) noexcept
10372 {
10373  auto mod_to_str = [](std::string& s, uint32_t m)
10374  {
10375  s += "[";
10376  std::string delim = "";
10377 
10379  {
10380  s += delim + "\"Shift\"";
10381  delim = ",";
10382  }
10383 
10385  {
10386  s += delim + "\"CapsLock\"";
10387  delim = ",";
10388  }
10389 
10391  {
10392  s += delim + "\"Control\"";
10393  delim = ",";
10394  }
10395 
10396  if(m & Yetani::KeyModifier_Alt)
10397  {
10398  s += delim + "\"Alt\"";
10399  delim = ",";
10400  }
10401 
10402  if(m & Yetani::KeyModifier_NumLock)
10403  {
10404  s += delim + "\"NumLock\"";
10405  }
10406 
10407  if(m & Yetani::KeyModifier_Meta)
10408  {
10409  s += delim + "\"Meta\"";
10410  }
10411 
10412  s += "]";
10413  };
10414 
10415  std::string str = "{ \"pressed\": ";
10416  mod_to_str(str, key_modifier.pressed);
10417 
10418  str += ", \"latched\": ";
10419  mod_to_str(str, key_modifier.latched);
10420 
10421  str += ", \"locked\": ";
10422  mod_to_str(str, key_modifier.locked);
10423 
10424  str += " }";
10425 
10426  return str;
10427 }
10428 
10429 
10437 std::string to_string(const Yetani::KeyState& key_state
10438  ) noexcept
10439 {
10440  switch(key_state)
10441  {
10442  case Yetani::KeyState::Pressed: return "Pressed";
10443  case Yetani::KeyState::Released: return "Released";
10444  case Yetani::KeyState::Repeat: return "Repeat";
10445  default: return "";
10446  }
10447 }
10448 
10449 
10457 std::string to_string(const Yetani::Output& output
10458  ) noexcept
10459 {
10460  return std::string()
10461  + "{ \"x\": " + std::to_string(output.x)
10462  + ", \"y\": " + std::to_string(output.y)
10463  + ", \"physical_width_mm\": " + std::to_string(output.physical_width_mm)
10464  + ", \"physical_height_mm\": " + std::to_string(output.physical_height_mm)
10465  + ", \"subpixel\": " + std::to_string(output.subpixel)
10466  + ", \"subpixel_name\": \"" + Yetani::outputSubpixelName(output.subpixel) + "\""
10467  + ", \"make\": \"" + output.make + "\""
10468  + ", \"model\": \"" + output.model + "\""
10469  + ", \"transform\": " + std::to_string(output.transform)
10470  + ", \"transform_name\": \"" + Yetani::outputTransformName(output.transform) + "\""
10471  + ", \"flags\": " + std::to_string(output.flags)
10472  + ", \"width\": " + std::to_string(output.width)
10473  + ", \"height\": " + std::to_string(output.height)
10474  + ", \"refresh_mHz\": " + std::to_string(output.refresh_mHz)
10475  + ", \"scale_factor\": " + std::to_string(output.scale_factor)
10476  + ", \"pixels_per_mm_horizontal\": " + std::to_string(output.pixels_per_mm_horizontal)
10477  + ", \"pixels_per_mm_vertical\": " + std::to_string(output.pixels_per_mm_vertical)
10478  + " }";
10479 }
10480 
10481 
10489 std::string to_string(const Yetani::PointMm& point
10490  ) noexcept
10491 {
10492  return std::string()
10493  + "{ \"time\": " + std::to_string(point.time)
10494  + ", \"x\": " + std::to_string(point.x)
10495  + ", \"y\": " + std::to_string(point.y)
10496  + " }";
10497 }
10498 
10499 
10507 std::string to_string(const Yetani::PointPercent& point
10508  ) noexcept
10509 {
10510  return std::string()
10511  + "{ \"time\": " + std::to_string(point.time)
10512  + ", \"x\": " + std::to_string(point.x)
10513  + ", \"y\": " + std::to_string(point.y)
10514  + " }";
10515 }
10516 
10517 
10525 std::string to_string(const Yetani::PointPixel& point
10526  ) noexcept
10527 {
10528  return std::string()
10529  + "{ \"time\": " + std::to_string(point.time)
10530  + ", \"x\": " + std::to_string(point.x)
10531  + ", \"y\": " + std::to_string(point.y)
10532  + " }";
10533 }
10534 
10535 
10543 std::string to_string(const Yetani::PointerAxis& axis
10544  ) noexcept
10545 {
10546  return std::string()
10547  + "{ \"time\": " + std::to_string(axis.time)
10548  + ", \"steps\": " + std::to_string(axis.steps)
10549  + ", \"distance\": " + std::to_string(axis.distance)
10550  + ", \"source\": " + zakero::to_string(axis.source)
10551  + ", \"type\": " + zakero::to_string(axis.type)
10552  + " }";
10553 }
10554 
10555 
10563 std::string to_string(const Yetani::PointerAxisSource& source
10564  ) noexcept
10565 {
10566  switch(source)
10567  {
10568  case Yetani::PointerAxisSource::Continuous: return "Continuous";
10569  case Yetani::PointerAxisSource::Finger: return "Finger";
10570  case Yetani::PointerAxisSource::Wheel: return "Wheel";
10571  case Yetani::PointerAxisSource::Wheel_Tilt: return "Wheel Tilt";
10572  case Yetani::PointerAxisSource::Unknown: [[fallthrough]];
10573  default: return "";
10574  }
10575 }
10576 
10577 
10585 std::string to_string(const Yetani::PointerAxisType& type
10586  ) noexcept
10587 {
10588  switch(type)
10589  {
10590  case Yetani::PointerAxisType::Horizontal: return "Horizontal";
10591  case Yetani::PointerAxisType::Vertical: return "Vertical";
10592  case Yetani::PointerAxisType::Unknown: [[fallthrough]];
10593  default: return "";
10594  }
10595 }
10596 
10597 
10605 std::string to_string(const Yetani::PointerButton& button
10606  ) noexcept
10607 {
10608  return std::string()
10609  + "{ \"code\": " + std::to_string(button.code)
10610  + ", \"state\": " + zakero::to_string(button.state)
10611  + " }";
10612 }
10613 
10614 
10622 std::string to_string(const Yetani::PointerButtonState& button_state
10623  ) noexcept
10624 {
10625  switch(button_state)
10626  {
10627  case Yetani::PointerButtonState::Pressed: return "Pressed";
10628  case Yetani::PointerButtonState::Released: return "Released";
10629  default: return "";
10630  }
10631 }
10632 
10633 
10641 std::string to_string(const Yetani::SizeMm& size
10642  ) noexcept
10643 {
10644  return std::string()
10645  + "{ \"width\": " + std::to_string(size.width)
10646  + ", \"height\": " + std::to_string(size.height)
10647  + " }";
10648 }
10649 
10650 
10658 std::string to_string(const Yetani::SizePercent& size
10659  ) noexcept
10660 {
10661  return std::string()
10662  + "{ \"width\": " + std::to_string(size.width)
10663  + ", \"height\": " + std::to_string(size.height)
10664  + " }";
10665 }
10666 
10667 
10675 std::string to_string(const Yetani::SizePixel& size
10676  ) noexcept
10677 {
10678  return std::string()
10679  + "{ \"width\": " + std::to_string(size.width)
10680  + ", \"height\": " + std::to_string(size.height)
10681  + " }";
10682 }
10683 
10684 
10692 std::string to_string(const Yetani::WindowMode& window_mode
10693  ) noexcept
10694 {
10695  switch(window_mode)
10696  {
10697  case Yetani::WindowMode::Fullscreen: return "Fullscreen";
10698  case Yetani::WindowMode::Maximized: return "Maximized";
10699  case Yetani::WindowMode::Normal: return "Normal";
10700  default: return "";
10701  }
10702 }
10703 
10704 
10719  , Yetani::PointMm& rhs
10720  ) noexcept
10721 {
10722  return zakero::equalish(lhs.x, rhs.x, 0.001)
10723  && zakero::equalish(lhs.y, rhs.y, 0.001)
10724  ;
10725 }
10726 
10727 
10742  , Yetani::PointPercent& rhs
10743  ) noexcept
10744 {
10745  return zakero::equalish(lhs.x, rhs.x, 0.00001)
10746  && zakero::equalish(lhs.y, rhs.y, 0.00001)
10747  ;
10748 }
10749 
10750 
10762  , Yetani::PointPixel& rhs
10763  ) noexcept
10764 {
10765  return (lhs.x == rhs.x) && (lhs.y == rhs.y);
10766 }
10767 
10768 
10781  , Yetani::SizeMm& rhs
10782  ) noexcept
10783 {
10784  return zakero::equalish(lhs.width, rhs.width, 0.001)
10785  && zakero::equalish(lhs.height, rhs.height, 0.001)
10786  ;
10787 }
10788 
10789 
10802  , Yetani::SizePercent& rhs
10803  ) noexcept
10804 {
10805  return zakero::equalish(lhs.width, rhs.width, 0.00001)
10806  && zakero::equalish(lhs.height, rhs.height, 0.00001)
10807  ;
10808 }
10809 
10810 
10820  , Yetani::SizePixel& rhs
10821  ) noexcept
10822 {
10823  return (lhs.width == rhs.width) && (lhs.height == rhs.height);
10824 }
10825 
10826 // }}}
10827 
10828 }
10829 
10830 #endif // ZAKERO_YETANI_IMPLEMENTATION
10831 
10832 // }}}
10833 
10834 #endif // zakero_Yetani_h
Zakero Base.
std::string to_string(const bool value) noexcept
Convert a bool into a string.
Definition: Zakero_Base.h:561
#define ZAKERO_STEADY_TIME_NOW(unit_)
Get the current time.
Definition: Zakero_Base.h:231
auto vectorErase(std::vector< Type > &vector, const Type &value) noexcept
Erase the contents of a std::vector.
Definition: Zakero_Base.h:503
bool vectorContains(const std::vector< Type > &vector, const Type &value) noexcept
Check the contents of a std::vector.
Definition: Zakero_Base.h:431
uint64_t convert(const uint64_t size, const zakero::Storage from, const zakero::Storage to) noexcept
Convert storage sizes.
Definition: Zakero_Base.h:319
bool equalish(const float a, const float b, const float delta) noexcept
Compare two floats.
Definition: Zakero_Base.h:375
Zakero MemoryPool.
bool operator==(const zakero::messagepack::Object &lhs, const zakero::messagepack::Object &rhs) noexcept
Compare two Objects for equality.
Definition: Zakero_MessagePack.h:8964
A pool of memory.
Definition: Zakero_MemoryPool.h:273
std::error_code init(const size_t, const bool=false, const MemoryPool::Alignment=MemoryPool::Alignment::Bits_64) noexcept
Initialize the MemoryPool.
Definition: Zakero_MemoryPool.h:648
size_t size() const noexcept
The size of the memory pool.
Definition: Zakero_MemoryPool.h:755
int fd() const noexcept
The backing file descriptor.
Definition: Zakero_MemoryPool.h:742
void sizeOnChange(MemoryPool::LambdaSize) noexcept
Set the Size Event callback.
Definition: Zakero_MemoryPool.h:790
A Window.
Definition: Zakero_Yetani.h:1320
std::error_code sizeSet(const Yetani::SizeMm &) noexcept
Set the window size.
Definition: Zakero_Yetani.h:9065
void imagePresent() noexcept
Render the image.
Definition: Zakero_Yetani.h:9400
struct wl_shm_pool * wl_shm_pool
A pointer to the Wayland Shared Memory Pool.
Definition: Zakero_Yetani.h:1424
zakero::MemoryPool memory_pool
The Window's Memory Pool.
Definition: Zakero_Yetani.h:1425
void onCloseRequest(Yetani::Lambda) noexcept
Respond to "Close Request" events.
Definition: Zakero_Yetani.h:9668
void pointerOnEnter(Yetani::LambdaPointMm) noexcept
Respond to "Pointer Enter" events.
Definition: Zakero_Yetani.h:10021
void onFocusChange(Yetani::LambdaBool) noexcept
Respond to "Active" change events.
Definition: Zakero_Yetani.h:9722
uint32_t time() const noexcept
When the last frame was rendered.
Definition: Zakero_Yetani.h:9432
Yetani::PointPixel convertToPixel(const Yetani::PointMm &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9524
std::error_code decorationsSet(const Yetani::WindowDecorations) noexcept
Use the Desktop Environment borders.
Definition: Zakero_Yetani.h:8949
void windowModeOnChange(Yetani::LambdaWindowMode) noexcept
Respond to "Window Mode" events.
Definition: Zakero_Yetani.h:9824
virtual ~Window()
Destroy a Window.
Definition: Zakero_Yetani.h:8813
void pointerOnLeave(Yetani::Lambda) noexcept
Respond to "Pointer Leave" events.
Definition: Zakero_Yetani.h:10111
void cursorShow() noexcept
Show the cursor.
Definition: Zakero_Yetani.h:8886
void pointerOnButton(Yetani::LambdaButtonMm) noexcept
Respond to "Pointer Button" events.
Definition: Zakero_Yetani.h:9934
void pointerOnAxisSource(Yetani::Lambda) noexcept
Respond to "Pointer Axis Source" events.
Definition: Zakero_Yetani.h:10249
uint8_t bytesPerPixel() const noexcept
Get the number of bytes per pixel.
Definition: Zakero_Yetani.h:9450
void sizeOnChange(Yetani::LambdaSizeMm) noexcept
Respond to "Resize" events.
Definition: Zakero_Yetani.h:9853
std::error_code cursorUse(const std::string &) noexcept
Use a cursor.
Definition: Zakero_Yetani.h:8858
void keyboardOnEnter(Yetani::Lambda) noexcept
Respond to "Keyboard Enter" events.
Definition: Zakero_Yetani.h:9743
bool windowModeIs(const Yetani::WindowMode) noexcept
Check the WindowMode.
Definition: Zakero_Yetani.h:8995
std::error_code sizeSetMinMax(const Yetani::SizeMm &, const Yetani::SizeMm &) noexcept
Set the minimum window size.
Definition: Zakero_Yetani.h:9203
void titleSet(const std::string &) noexcept
Change the window title.
Definition: Zakero_Yetani.h:8923
void pointerOnMotion(Yetani::LambdaPointMm) noexcept
Respond to "Pointer Motion" events.
Definition: Zakero_Yetani.h:10139
Yetani::PointPercent convertToPercent(const Yetani::PointPixel &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9501
void classSet(const std::string &) noexcept
Change the window class.
Definition: Zakero_Yetani.h:8910
void pointerOnAxisDiscrete(Yetani::Lambda) noexcept
Respond to "Pointer Axis Discrete" events.
Definition: Zakero_Yetani.h:10303
void windowModeSet(const Yetani::WindowMode) noexcept
Change the window mode.
Definition: Zakero_Yetani.h:9019
Yetani::WindowMode windowMode() noexcept
Get the current WindowMode.
Definition: Zakero_Yetani.h:8977
std::error_code imageNext(uint8_t *&, Yetani::SizePixel &) noexcept
Get an image buffer.
Definition: Zakero_Yetani.h:9364
void pointerOnAxisStop(Yetani::Lambda) noexcept
Respond to "Pointer Axis Stop" events.
Definition: Zakero_Yetani.h:10276
void decorationsOnChange(Yetani::LambdaWindowDecorations) noexcept
Respond to "Decoration Change" events.
Definition: Zakero_Yetani.h:9693
Window(void *)
Construct a Window.
Definition: Zakero_Yetani.h:8760
void keyboardOnKey(Yetani::LambdaKey) noexcept
Respond to "Keyboard Key" events.
Definition: Zakero_Yetani.h:9797
void cursorHide() noexcept
Hide the cursor.
Definition: Zakero_Yetani.h:8875
void minimize() noexcept
Minimize the window.
Definition: Zakero_Yetani.h:9463
Yetani::PointMm convertToMm(const Yetani::PointPixel &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9478
void pointerOnAxis(Yetani::LambdaAxis) noexcept
Respond to "Pointer Axis" events.
Definition: Zakero_Yetani.h:10222
void keyboardOnLeave(Yetani::Lambda) noexcept
Respond to "Keyboard Leave" events.
Definition: Zakero_Yetani.h:9769
The shared memory.
Definition: Zakero_Yetani.h:1423
A wrapper class for Wayland.
Definition: Zakero_Yetani.h:1033
uint32_t code
The key code of the event.
Definition: Zakero_Yetani.h:1053
std::string make
Description of the manufacturer.
Definition: Zakero_Yetani.h:1206
static std::string outputTransformName(int32_t) noexcept
Get a human readable string.
Definition: Zakero_Yetani.h:4791
float pixels_per_mm_vertical
A pre-calculated value.
Definition: Zakero_Yetani.h:1220
std::function< void(const Yetani::Key &, const Yetani::KeyModifier &)> LambdaKey
A Lambda that has parameters: Key and KeyModifier.
Definition: Zakero_Yetani.h:1302
static std::string outputSubpixelName(int32_t) noexcept
Get a human readable string.
Definition: Zakero_Yetani.h:4766
float pixels_per_mm_horizontal
A pre-calculated value.
Definition: Zakero_Yetani.h:1219
float distance
The distance traveled.
Definition: Zakero_Yetani.h:1123
const std::vector< void * > & image_data
A collection of image data.
Definition: Zakero_Yetani.h:1187
std::function< void(const Yetani::PointerButton &, const Yetani::PointPercent &, const Yetani::KeyModifier &)> LambdaButtonPercent
A Lambda that has parameters: PointerButton, PointPercent and KeyModifier.
Definition: Zakero_Yetani.h:1305
static std::string shmFormatName(const wl_shm_format) noexcept
Get the name of the format.
Definition: Zakero_Yetani.h:4491
Yetani::VectorOutputId outputVector() const noexcept
Get a list of the Output Id's.
Definition: Zakero_Yetani.h:4740
int32_t height
The height of the device in hardware units.
Definition: Zakero_Yetani.h:1211
int32_t keyRepeatDelay() const noexcept
The key repeat delay.
Definition: Zakero_Yetani.h:5451
static constexpr uint32_t KeyModifier_Alt
Key Modifier flag.
Definition: Zakero_Yetani.h:1060
uint32_t pressed
A collection of pressed modifiers.
Definition: Zakero_Yetani.h:1066
void outputOnAdd(Yetani::LambdaOutputId) noexcept
Notification of adding an Output device.
Definition: Zakero_Yetani.h:5052
Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointMm &) const noexcept
Convert Millimeter to Pixel.
Definition: Zakero_Yetani.h:4875
Yetani::PointerAxisType type
The type of Axis.
Definition: Zakero_Yetani.h:1125
static constexpr uint32_t KeyModifier_Meta
Key Modifier flag.
Definition: Zakero_Yetani.h:1062
Yetani::PointPercent outputConvertToPercent(const Yetani::OutputId, const Yetani::PointPixel &) const noexcept
Convert Pixel to a Percentage.
Definition: Zakero_Yetani.h:4845
Yetani::Output output(const Yetani::OutputId) const noexcept
Get a copy of the Output information.
Definition: Zakero_Yetani.h:4708
int32_t y
The Y position within the global compositor.
Definition: Zakero_Yetani.h:1209
Yetani::Window * windowCreate(const Yetani::SizeMm &, std::error_code &) noexcept
Create a window.
Definition: Zakero_Yetani.h:8024
PointerAxisType
The direction of the axis movement.
Definition: Zakero_Yetani.h:1114
void outputOnChange(Yetani::LambdaOutputId) noexcept
Notification that an Output device has changed.
Definition: Zakero_Yetani.h:5075
Yetani::PointerButtonState state
The button state.
Definition: Zakero_Yetani.h:1139
PointerButtonState
Mouse button state.
Definition: Zakero_Yetani.h:1132
uint32_t time
When the key event happened.
Definition: Zakero_Yetani.h:1052
std::function< void(Yetani::WindowMode)> LambdaWindowMode
A Lambda that has a parameter: WindowMode.
Definition: Zakero_Yetani.h:1312
std::function< void(const Yetani::PointerButton &, const Yetani::PointPixel &, const Yetani::KeyModifier &)> LambdaButtonPixel
A Lambda that has parameters: PointerButton, PointPixel and KeyModifier.
Definition: Zakero_Yetani.h:1306
uint32_t flags
wl_output_mode bitfield properties.
Definition: Zakero_Yetani.h:1218
static constexpr wl_shm_format SHM_FORMAT_DEFAULT
The default pixel format.
Definition: Zakero_Yetani.h:1444
static constexpr uint32_t KeyModifier_CapsLock
Key Modifier flag.
Definition: Zakero_Yetani.h:1058
void outputOnRemove(Yetani::LambdaOutputId) noexcept
Notification of removing an Output device.
Definition: Zakero_Yetani.h:5098
PointerAxisSource
Where the axis information came from.
Definition: Zakero_Yetani.h:1106
std::function< void(const Yetani::PointerAxis &, const Yetani::KeyModifier &)> LambdaAxis
A Lambda that has parameters: PointerAxis and KeyModifier.
Definition: Zakero_Yetani.h:1303
std::function< void(const Yetani::PointMm &, const Yetani::KeyModifier &)> LambdaPointMm
A Lambda that has parameters: PointMm and KeyModifier.
Definition: Zakero_Yetani.h:1307
uint32_t latched
A collection of latched modifiers.
Definition: Zakero_Yetani.h:1067
static Yetani * connect() noexcept
Establish a connection with the Wayland Compositor.
Definition: Zakero_Yetani.h:3318
std::error_code cursorCreate(const std::string &, const Yetani::CursorConfig &) noexcept
Create a cursor.
Definition: Zakero_Yetani.h:3801
std::function< void(const Yetani::PointPercent &, const Yetani::KeyModifier &)> LambdaPointPercent
A Lambda that has parameters: PointPercent and KeyModifier.
Definition: Zakero_Yetani.h:1308
std::function< void()> Lambda
A Lambda that has no parameters.
Definition: Zakero_Yetani.h:1301
uint32_t physical_height_mm
The height of the device in millimeters.
Definition: Zakero_Yetani.h:1213
uint32_t physical_width_mm
The width of the device in millimeters.
Definition: Zakero_Yetani.h:1212
int32_t keyRepeatRate() const noexcept
The key repeat rate.
Definition: Zakero_Yetani.h:5465
std::function< void(const Yetani::SizeMm &)> LambdaSizeMm
A Lambda that has a parameter: SizeMm.
Definition: Zakero_Yetani.h:1313
std::string model
Description of the model.
Definition: Zakero_Yetani.h:1207
const Yetani::VectorShmFormat & shmFormatAvailable() const noexcept
Get all the support color formats.
Definition: Zakero_Yetani.h:4426
std::error_code cursorDestroy(const std::string &) noexcept
Destroy a cursor.
Definition: Zakero_Yetani.h:3939
std::function< void(const Yetani::SizePercent &)> LambdaSizePercent
A Lambda that has a parameter: SizePercent.
Definition: Zakero_Yetani.h:1314
WindowDecorations
Who is responsible for rendering the decorations.
Definition: Zakero_Yetani.h:1289
KeyState
Keyboard key state
Definition: Zakero_Yetani.h:1045
int32_t refresh_mHz
The current refresh rate of the device.
Definition: Zakero_Yetani.h:1215
uint32_t time
When the event occurred.
Definition: Zakero_Yetani.h:1121
int32_t x
The X position within the global compositor.
Definition: Zakero_Yetani.h:1208
int32_t width
The width of the device in hardware units.
Definition: Zakero_Yetani.h:1210
uint32_t group
The keyboard layout.
Definition: Zakero_Yetani.h:1069
std::function< void(const Yetani::PointPixel &, const Yetani::KeyModifier &)> LambdaPointPixel
A Lambda that has parameters: PointPixel and KeyModifier.
Definition: Zakero_Yetani.h:1309
int32_t scale_factor
The scaling factor between the device and compositor.
Definition: Zakero_Yetani.h:1216
std::function< void(bool)> LambdaBool
A Lambda that has a parameter: bool.
Definition: Zakero_Yetani.h:1310
virtual ZAKERO_YETANI__ERROR_DATA ~Yetani() noexcept
Destructor.
Definition: Zakero_Yetani.h:3282
std::function< void(const Yetani::PointerButton &, const Yetani::PointMm &, const Yetani::KeyModifier &)> LambdaButtonMm
A Lambda that has parameters: PointerButton, PointMm and KeyModifier.
Definition: Zakero_Yetani.h:1304
WindowMode
Definition: Zakero_Yetani.h:1294
int32_t steps
The number of rotation steps.
Definition: Zakero_Yetani.h:1122
KeyState state
The state of the key.
Definition: Zakero_Yetani.h:1054
std::function< void(const Yetani::SizePixel &)> LambdaSizePixel
A Lambda that has a parameter: SizePixel.
Definition: Zakero_Yetani.h:1315
int32_t subpixel
The device's subpixel orientation.
Definition: Zakero_Yetani.h:1214
std::function< void(Yetani::WindowDecorations)> LambdaWindowDecorations
A Lambda that has a parameter: WindowDecorations.
Definition: Zakero_Yetani.h:1311
static constexpr uint32_t KeyModifier_Control
Key Modifier flag.
Definition: Zakero_Yetani.h:1059
static uint8_t shmFormatBytesPerPixel(const wl_shm_format) noexcept
Determine bytes-per-pixel.
Definition: Zakero_Yetani.h:4443
static constexpr uint32_t KeyModifier_Shift
Key Modifier flag.
Definition: Zakero_Yetani.h:1057
uint32_t code
The event code.
Definition: Zakero_Yetani.h:1138
Yetani::PointMm outputConvertToMm(const Yetani::OutputId, const Yetani::PointPixel &) const noexcept
Convert Pixel to Millimeter.
Definition: Zakero_Yetani.h:4815
Yetani::PointerAxisSource source
The source of the event.
Definition: Zakero_Yetani.h:1124
int32_t transform
Transform that maps framebuffer to output.
Definition: Zakero_Yetani.h:1217
static std::string shmFormatDescription(const wl_shm_format) noexcept
Get a description of the format.
Definition: Zakero_Yetani.h:4468
uint32_t locked
A collection of locked modifiers.
Definition: Zakero_Yetani.h:1068
Cursor configuration.
Definition: Zakero_Yetani.h:1181
Key event information.
Definition: Zakero_Yetani.h:1051
A collection modifier flags.
Definition: Zakero_Yetani.h:1065
Information about a output device.
Definition: Zakero_Yetani.h:1205
Information about an Axis event.
Definition: Zakero_Yetani.h:1120
Information about a pointer button event.
Definition: Zakero_Yetani.h:1137
A location that uses millimeters.
Definition: Zakero_Yetani.h:1076
float x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1078
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1077
float y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1079
friend bool operator==(Yetani::PointMm &, Yetani::PointMm &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10718
A location that uses percentages.
Definition: Zakero_Yetani.h:1085
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1086
float x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1087
friend bool operator==(Yetani::PointPercent &, Yetani::PointPercent &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10741
float y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1088
A location that uses pixels.
Definition: Zakero_Yetani.h:1094
friend bool operator==(Yetani::PointPixel &, Yetani::PointPixel &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10761
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1095
int32_t x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1096
int32_t y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1097
Size measured in millimeters.
Definition: Zakero_Yetani.h:1146
friend bool operator==(Yetani::SizeMm &, Yetani::SizeMm &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10780
float width
The width.
Definition: Zakero_Yetani.h:1147
float height
The height.
Definition: Zakero_Yetani.h:1148
Size measured as a percentage of the Output (Monitor) resolution.
Definition: Zakero_Yetani.h:1154
float width
The width.
Definition: Zakero_Yetani.h:1155
float height
The height.
Definition: Zakero_Yetani.h:1156
friend bool operator==(Yetani::SizePercent &, Yetani::SizePercent &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10801
Size measured in pixels.
Definition: Zakero_Yetani.h:1162
friend bool operator==(Yetani::SizePixel &, Yetani::SizePixel &) noexcept
Compare two Size objects.
Definition: Zakero_Yetani.h:10819
int32_t width
The width.
Definition: Zakero_Yetani.h:1163
int32_t height
The height.
Definition: Zakero_Yetani.h:1164