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 
216 /******************************************************************************
217  * Includes
218  */
219 
220 #include <iostream>
221 #include <thread>
222 
223 // POSIX
224 #include <poll.h>
225 
226 // Linux
227 #include <linux/input-event-codes.h>
228 
229 // Wayland
230 #include <wayland/wayland-client.h>
231 
232 // Zakero
233 #include "Zakero_Base.h"
234 #include "Zakero_MemoryPool.h"
235 
236 
237 /******************************************************************************
238  * Macros
239  */
240 
241 // {{{ Macros
242 
259 #define ZAKERO_YETANI__ERROR_DATA \
260  X(Error_None , 0 , "No Error" ) \
261  X(Error_Compositor_Was_Not_Found , 1 , "Could not find the Compositor object in the Global Repository." ) \
262  X(Error_Connection_Failed , 2 , "Failed to connect to the Wayland Server." ) \
263  X(Error_Cursor_Already_Exists , 3 , "A cursor with that name already exists." ) \
264  X(Error_Cursor_Does_Not_Exist , 4 , "No cursors exists with that name." ) \
265  X(Error_Cursor_Frame_Time_Too_Large , 5 , "The cursor time per frame is too large, must be <= Size_Max." ) \
266  X(Error_Cursor_Frame_Time_Too_Small , 6 , "The cursor time per frame is too small, must be greater than 0." ) \
267  X(Error_Cursor_Image_Data_Is_Empty , 7 , "The cursor image data can not be empty." ) \
268  X(Error_Cursor_Name_Is_Invalid , 8 , "The cursor name is invalid." ) \
269  X(Error_Cursor_Not_Attached , 9 , "The specified cursor is not attached/in-use." ) \
270  X(Error_Cursor_Size_Too_Small , 10 , "The cursor size, both width and height must be greater than 0." ) \
271  X(Error_Invalid_Display_Name , 11 , "An invalid dispaly name was given to the Wayland Server." ) \
272  X(Error_Minimum_Size_Greater_Than_Maximum_Size , 12 , "The minimum window size is larger than the maximum window size." ) \
273  X(Error_No_Output_Available , 13 , "No output devices are available." ) \
274  X(Error_Registry_Not_Available , 14 , "Unable to get the registery." ) \
275  X(Error_Server_Side_Decorations_Not_Available , 15 , "The Wayland Compositor does not support Server Side Decorations." ) \
276  X(Error_Shm_Was_Not_Found , 16 , "Could not find the Shm object in the Global Repository." ) \
277  X(Error_Wayland_Not_Available , 17 , "Could not find the Wayland Server." ) \
278  X(Error_Window_Initialization_Failed , 18 , "The window was not able to be initialized." ) \
279  X(Error_Window_Size_Too_Small , 19 , "The window size was too small." ) \
280  X(Error_Xdg_WM_Base_Was_Not_Found , 20 , "Could not find the XDG WM Base object the Global Repository." ) \
281 
282  /* --- To Be Deleted --- */
283  /*
284  X(Error_Window_Already_Exists , 100 , "A window with that name already exists." ) \
285  X(Error_Window_Does_Not_Exist , 101 , "No windows exists with that name." ) \
286  X(Error_Window_Name_Can_Not_Be_Empty , 102 , "Windows can not have empty names." ) \
287  X(Error_EventLoop_Is_Already_Running , 103 , "Can't start the event loop since it is already running." ) \
288  X(Error_Connection_Not_Initialized , 104 , "Not connected to the Wayland Server." ) \
289  X(Error_Connection_Already_Established , 105 , "Must disconnect before establishing a new connection." ) \
290  X(Error_Seat_Was_Not_Found , 106 , "Could not find the Seat object in the Global Repository." ) \
291  X(Error_Present_Current_Image_First , 107 , "The next image has already been retrieved and must be presented." ) \
292  X(Error_No_Image_Is_Available , 108 , "No image is available to be retrieved." ) \
293  X(Error_Window_Is_Locked , 109 , "The window access is restricted due to being locked." ) \
294  X(Error_Cursor_Image_Data_Size_Is_Invalid , 110 , "The cursor image data size does not match the configuration." ) \
295  */
296 
297 // }}}
298 
299 /******************************************************************************
300  * Generated Code
301  *
302  * The code is this section was created by "wayland-protocol/protocol.sh". The
303  * generated code is required since the XDG/Wayland headers are not officially
304  * distributed. Plus, there are many versions of the generated code with
305  * slight variations. By including the code directly, the generated code is
306  * from a known baseline.
307  *
308  * TL;DR: The code you are looking for is in the Yetani class.
309  */
310 
315 /*
316  * The "wayland-protocol/protocol.sh" script uses this fold as markers to know
317  * where to add and remove code.
318  */
319 // {{{ Generated Code
320 // {{{ xdg-decoration-unstable-v1
321 struct xdg_toplevel;
322 struct zxdg_decoration_manager_v1;
323 struct zxdg_toplevel_decoration_v1;
324 extern const struct wl_interface zxdg_decoration_manager_v1_interface;
325 extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
326 static inline void
327 zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data)
328 {
329  wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data);
330 }
331 static inline void *
332 zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
333 {
334  return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1);
335 }
336 static inline uint32_t
337 zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
338 {
339  return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1);
340 }
341 static inline void
342 zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
343 {
344  wl_proxy_marshal((struct wl_proxy *) zxdg_decoration_manager_v1,
345  0);
346  wl_proxy_destroy((struct wl_proxy *) zxdg_decoration_manager_v1);
347 }
348 static inline struct zxdg_toplevel_decoration_v1 *
349 zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel)
350 {
351  struct wl_proxy *id;
352  id = wl_proxy_marshal_constructor((struct wl_proxy *) zxdg_decoration_manager_v1,
353  1, &zxdg_toplevel_decoration_v1_interface, NULL, toplevel);
354  return (struct zxdg_toplevel_decoration_v1 *) id;
355 }
356 enum zxdg_toplevel_decoration_v1_error {
357  ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0,
358  ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1,
359  ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2,
360 };
361 enum zxdg_toplevel_decoration_v1_mode {
362  ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1,
363  ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2,
364 };
365 struct zxdg_toplevel_decoration_v1_listener {
366  void (*configure)(void *data,
367  struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
368  uint32_t mode);
369 };
370 static inline int
371 zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
372  const struct zxdg_toplevel_decoration_v1_listener *listener, void *data)
373 {
374  return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1,
375  (void (**)(void)) listener, data);
376 }
377 static inline void
378 zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data)
379 {
380  wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data);
381 }
382 static inline void *
383 zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
384 {
385  return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1);
386 }
387 static inline uint32_t
388 zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
389 {
390  return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1);
391 }
392 static inline void
393 zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
394 {
395  wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
396  0);
397  wl_proxy_destroy((struct wl_proxy *) zxdg_toplevel_decoration_v1);
398 }
399 static inline void
400 zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode)
401 {
402  wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
403  1, mode);
404 }
405 static inline void
406 zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
407 {
408  wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
409  2);
410 }
411 #ifdef ZAKERO_YETANI_IMPLEMENTATION
412 extern const struct wl_interface xdg_toplevel_interface;
413 extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
414 static const struct wl_interface *xdg_decoration_unstable_v1_types[] = {
415  NULL,
416  &zxdg_toplevel_decoration_v1_interface,
417  &xdg_toplevel_interface,
418 };
419 static const struct wl_message zxdg_decoration_manager_v1_requests[] = {
420  { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
421  { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 },
422 };
423 const struct wl_interface zxdg_decoration_manager_v1_interface = {
424  "zxdg_decoration_manager_v1", 1,
425  2, zxdg_decoration_manager_v1_requests,
426  0, NULL,
427 };
428 static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = {
429  { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
430  { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 },
431  { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 },
432 };
433 static const struct wl_message zxdg_toplevel_decoration_v1_events[] = {
434  { "configure", "u", xdg_decoration_unstable_v1_types + 0 },
435 };
436 const struct wl_interface zxdg_toplevel_decoration_v1_interface = {
437  "zxdg_toplevel_decoration_v1", 1,
438  3, zxdg_toplevel_decoration_v1_requests,
439  1, zxdg_toplevel_decoration_v1_events,
440 };
441 #endif // ZAKERO_YETANI_IMPLEMENTATION
442 // }}}
443 // {{{ xdg-shell
444 struct wl_output;
445 struct wl_seat;
446 struct wl_surface;
447 struct xdg_popup;
448 struct xdg_positioner;
449 struct xdg_surface;
450 struct xdg_toplevel;
451 struct xdg_wm_base;
452 extern const struct wl_interface xdg_wm_base_interface;
453 extern const struct wl_interface xdg_positioner_interface;
454 extern const struct wl_interface xdg_surface_interface;
455 extern const struct wl_interface xdg_toplevel_interface;
456 extern const struct wl_interface xdg_popup_interface;
457 enum xdg_wm_base_error {
458  XDG_WM_BASE_ERROR_ROLE = 0,
459  XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1,
460  XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2,
461  XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3,
462  XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4,
463  XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5,
464 };
465 struct xdg_wm_base_listener {
466  void (*ping)(void *data,
467  struct xdg_wm_base *xdg_wm_base,
468  uint32_t serial);
469 };
470 static inline int
471 xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base,
472  const struct xdg_wm_base_listener *listener, void *data)
473 {
474  return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base,
475  (void (**)(void)) listener, data);
476 }
477 static inline void
478 xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data)
479 {
480  wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data);
481 }
482 static inline void *
483 xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base)
484 {
485  return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base);
486 }
487 static inline uint32_t
488 xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base)
489 {
490  return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base);
491 }
492 static inline void
493 xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base)
494 {
495  wl_proxy_marshal((struct wl_proxy *) xdg_wm_base,
496  0);
497  wl_proxy_destroy((struct wl_proxy *) xdg_wm_base);
498 }
499 static inline struct xdg_positioner *
500 xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base)
501 {
502  struct wl_proxy *id;
503  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base,
504  1, &xdg_positioner_interface, NULL);
505  return (struct xdg_positioner *) id;
506 }
507 static inline struct xdg_surface *
508 xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface)
509 {
510  struct wl_proxy *id;
511  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base,
512  2, &xdg_surface_interface, NULL, surface);
513  return (struct xdg_surface *) id;
514 }
515 static inline void
516 xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial)
517 {
518  wl_proxy_marshal((struct wl_proxy *) xdg_wm_base,
519  3, serial);
520 }
521 enum xdg_positioner_error {
522  XDG_POSITIONER_ERROR_INVALID_INPUT = 0,
523 };
524 enum xdg_positioner_anchor {
525  XDG_POSITIONER_ANCHOR_NONE = 0,
526  XDG_POSITIONER_ANCHOR_TOP = 1,
527  XDG_POSITIONER_ANCHOR_BOTTOM = 2,
528  XDG_POSITIONER_ANCHOR_LEFT = 3,
529  XDG_POSITIONER_ANCHOR_RIGHT = 4,
530  XDG_POSITIONER_ANCHOR_TOP_LEFT = 5,
531  XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6,
532  XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7,
533  XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8,
534 };
535 enum xdg_positioner_gravity {
536  XDG_POSITIONER_GRAVITY_NONE = 0,
537  XDG_POSITIONER_GRAVITY_TOP = 1,
538  XDG_POSITIONER_GRAVITY_BOTTOM = 2,
539  XDG_POSITIONER_GRAVITY_LEFT = 3,
540  XDG_POSITIONER_GRAVITY_RIGHT = 4,
541  XDG_POSITIONER_GRAVITY_TOP_LEFT = 5,
542  XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6,
543  XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7,
544  XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8,
545 };
546 enum xdg_positioner_constraint_adjustment {
547  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0,
548  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1,
549  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2,
550  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4,
551  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8,
552  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16,
553  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32,
554 };
555 static inline void
556 xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data)
557 {
558  wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data);
559 }
560 static inline void *
561 xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner)
562 {
563  return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner);
564 }
565 static inline uint32_t
566 xdg_positioner_get_version(struct xdg_positioner *xdg_positioner)
567 {
568  return wl_proxy_get_version((struct wl_proxy *) xdg_positioner);
569 }
570 static inline void
571 xdg_positioner_destroy(struct xdg_positioner *xdg_positioner)
572 {
573  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
574  0);
575  wl_proxy_destroy((struct wl_proxy *) xdg_positioner);
576 }
577 static inline void
578 xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height)
579 {
580  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
581  1, width, height);
582 }
583 static inline void
584 xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height)
585 {
586  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
587  2, x, y, width, height);
588 }
589 static inline void
590 xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor)
591 {
592  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
593  3, anchor);
594 }
595 static inline void
596 xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity)
597 {
598  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
599  4, gravity);
600 }
601 static inline void
602 xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment)
603 {
604  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
605  5, constraint_adjustment);
606 }
607 static inline void
608 xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y)
609 {
610  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
611  6, x, y);
612 }
613 static inline void
614 xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner)
615 {
616  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
617  7);
618 }
619 static inline void
620 xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height)
621 {
622  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
623  8, parent_width, parent_height);
624 }
625 static inline void
626 xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial)
627 {
628  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
629  9, serial);
630 }
631 enum xdg_surface_error {
632  XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1,
633  XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2,
634  XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3,
635 };
636 struct xdg_surface_listener {
637  void (*configure)(void *data,
638  struct xdg_surface *xdg_surface,
639  uint32_t serial);
640 };
641 static inline int
642 xdg_surface_add_listener(struct xdg_surface *xdg_surface,
643  const struct xdg_surface_listener *listener, void *data)
644 {
645  return wl_proxy_add_listener((struct wl_proxy *) xdg_surface,
646  (void (**)(void)) listener, data);
647 }
648 static inline void
649 xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)
650 {
651  wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data);
652 }
653 static inline void *
654 xdg_surface_get_user_data(struct xdg_surface *xdg_surface)
655 {
656  return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface);
657 }
658 static inline uint32_t
659 xdg_surface_get_version(struct xdg_surface *xdg_surface)
660 {
661  return wl_proxy_get_version((struct wl_proxy *) xdg_surface);
662 }
663 static inline void
664 xdg_surface_destroy(struct xdg_surface *xdg_surface)
665 {
666  wl_proxy_marshal((struct wl_proxy *) xdg_surface,
667  0);
668  wl_proxy_destroy((struct wl_proxy *) xdg_surface);
669 }
670 static inline struct xdg_toplevel *
671 xdg_surface_get_toplevel(struct xdg_surface *xdg_surface)
672 {
673  struct wl_proxy *id;
674  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface,
675  1, &xdg_toplevel_interface, NULL);
676  return (struct xdg_toplevel *) id;
677 }
678 static inline struct xdg_popup *
679 xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner)
680 {
681  struct wl_proxy *id;
682  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface,
683  2, &xdg_popup_interface, NULL, parent, positioner);
684  return (struct xdg_popup *) id;
685 }
686 static inline void
687 xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height)
688 {
689  wl_proxy_marshal((struct wl_proxy *) xdg_surface,
690  3, x, y, width, height);
691 }
692 static inline void
693 xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)
694 {
695  wl_proxy_marshal((struct wl_proxy *) xdg_surface,
696  4, serial);
697 }
698 enum xdg_toplevel_resize_edge {
699  XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0,
700  XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1,
701  XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2,
702  XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4,
703  XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5,
704  XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6,
705  XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8,
706  XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9,
707  XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10,
708 };
709 enum xdg_toplevel_state {
710  XDG_TOPLEVEL_STATE_MAXIMIZED = 1,
711  XDG_TOPLEVEL_STATE_FULLSCREEN = 2,
712  XDG_TOPLEVEL_STATE_RESIZING = 3,
713  XDG_TOPLEVEL_STATE_ACTIVATED = 4,
714  XDG_TOPLEVEL_STATE_TILED_LEFT = 5,
715  XDG_TOPLEVEL_STATE_TILED_RIGHT = 6,
716  XDG_TOPLEVEL_STATE_TILED_TOP = 7,
717  XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8,
718 };
719 struct xdg_toplevel_listener {
720  void (*configure)(void *data,
721  struct xdg_toplevel *xdg_toplevel,
722  int32_t width,
723  int32_t height,
724  struct wl_array *states);
725  void (*close)(void *data,
726  struct xdg_toplevel *xdg_toplevel);
727 };
728 static inline int
729 xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel,
730  const struct xdg_toplevel_listener *listener, void *data)
731 {
732  return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel,
733  (void (**)(void)) listener, data);
734 }
735 static inline void
736 xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data)
737 {
738  wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data);
739 }
740 static inline void *
741 xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel)
742 {
743  return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel);
744 }
745 static inline uint32_t
746 xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel)
747 {
748  return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel);
749 }
750 static inline void
751 xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel)
752 {
753  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
754  0);
755  wl_proxy_destroy((struct wl_proxy *) xdg_toplevel);
756 }
757 static inline void
758 xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent)
759 {
760  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
761  1, parent);
762 }
763 static inline void
764 xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title)
765 {
766  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
767  2, title);
768 }
769 static inline void
770 xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id)
771 {
772  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
773  3, app_id);
774 }
775 static inline void
776 xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
777 {
778  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
779  4, seat, serial, x, y);
780 }
781 static inline void
782 xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial)
783 {
784  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
785  5, seat, serial);
786 }
787 static inline void
788 xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges)
789 {
790  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
791  6, seat, serial, edges);
792 }
793 static inline void
794 xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
795 {
796  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
797  7, width, height);
798 }
799 static inline void
800 xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
801 {
802  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
803  8, width, height);
804 }
805 static inline void
806 xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel)
807 {
808  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
809  9);
810 }
811 static inline void
812 xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel)
813 {
814  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
815  10);
816 }
817 static inline void
818 xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output)
819 {
820  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
821  11, output);
822 }
823 static inline void
824 xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel)
825 {
826  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
827  12);
828 }
829 static inline void
830 xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel)
831 {
832  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
833  13);
834 }
835 enum xdg_popup_error {
836  XDG_POPUP_ERROR_INVALID_GRAB = 0,
837 };
838 struct xdg_popup_listener {
839  void (*configure)(void *data,
840  struct xdg_popup *xdg_popup,
841  int32_t x,
842  int32_t y,
843  int32_t width,
844  int32_t height);
845  void (*popup_done)(void *data,
846  struct xdg_popup *xdg_popup);
847  void (*repositioned)(void *data,
848  struct xdg_popup *xdg_popup,
849  uint32_t token);
850 };
851 static inline int
852 xdg_popup_add_listener(struct xdg_popup *xdg_popup,
853  const struct xdg_popup_listener *listener, void *data)
854 {
855  return wl_proxy_add_listener((struct wl_proxy *) xdg_popup,
856  (void (**)(void)) listener, data);
857 }
858 static inline void
859 xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data)
860 {
861  wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data);
862 }
863 static inline void *
864 xdg_popup_get_user_data(struct xdg_popup *xdg_popup)
865 {
866  return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup);
867 }
868 static inline uint32_t
869 xdg_popup_get_version(struct xdg_popup *xdg_popup)
870 {
871  return wl_proxy_get_version((struct wl_proxy *) xdg_popup);
872 }
873 static inline void
874 xdg_popup_destroy(struct xdg_popup *xdg_popup)
875 {
876  wl_proxy_marshal((struct wl_proxy *) xdg_popup,
877  0);
878  wl_proxy_destroy((struct wl_proxy *) xdg_popup);
879 }
880 static inline void
881 xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial)
882 {
883  wl_proxy_marshal((struct wl_proxy *) xdg_popup,
884  1, seat, serial);
885 }
886 static inline void
887 xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token)
888 {
889  wl_proxy_marshal((struct wl_proxy *) xdg_popup,
890  2, positioner, token);
891 }
892 #ifdef ZAKERO_YETANI_IMPLEMENTATION
893 extern const struct wl_interface wl_output_interface;
894 extern const struct wl_interface wl_seat_interface;
895 extern const struct wl_interface wl_surface_interface;
896 extern const struct wl_interface xdg_popup_interface;
897 extern const struct wl_interface xdg_positioner_interface;
898 extern const struct wl_interface xdg_surface_interface;
899 extern const struct wl_interface xdg_toplevel_interface;
900 static const struct wl_interface *xdg_shell_types[] = {
901  NULL,
902  NULL,
903  NULL,
904  NULL,
905  &xdg_positioner_interface,
906  &xdg_surface_interface,
907  &wl_surface_interface,
908  &xdg_toplevel_interface,
909  &xdg_popup_interface,
910  &xdg_surface_interface,
911  &xdg_positioner_interface,
912  &xdg_toplevel_interface,
913  &wl_seat_interface,
914  NULL,
915  NULL,
916  NULL,
917  &wl_seat_interface,
918  NULL,
919  &wl_seat_interface,
920  NULL,
921  NULL,
922  &wl_output_interface,
923  &wl_seat_interface,
924  NULL,
925  &xdg_positioner_interface,
926  NULL,
927 };
928 static const struct wl_message xdg_wm_base_requests[] = {
929  { "destroy", "", xdg_shell_types + 0 },
930  { "create_positioner", "n", xdg_shell_types + 4 },
931  { "get_xdg_surface", "no", xdg_shell_types + 5 },
932  { "pong", "u", xdg_shell_types + 0 },
933 };
934 static const struct wl_message xdg_wm_base_events[] = {
935  { "ping", "u", xdg_shell_types + 0 },
936 };
937 const struct wl_interface xdg_wm_base_interface = {
938  "xdg_wm_base", 3,
939  4, xdg_wm_base_requests,
940  1, xdg_wm_base_events,
941 };
942 static const struct wl_message xdg_positioner_requests[] = {
943  { "destroy", "", xdg_shell_types + 0 },
944  { "set_size", "ii", xdg_shell_types + 0 },
945  { "set_anchor_rect", "iiii", xdg_shell_types + 0 },
946  { "set_anchor", "u", xdg_shell_types + 0 },
947  { "set_gravity", "u", xdg_shell_types + 0 },
948  { "set_constraint_adjustment", "u", xdg_shell_types + 0 },
949  { "set_offset", "ii", xdg_shell_types + 0 },
950  { "set_reactive", "3", xdg_shell_types + 0 },
951  { "set_parent_size", "3ii", xdg_shell_types + 0 },
952  { "set_parent_configure", "3u", xdg_shell_types + 0 },
953 };
954 const struct wl_interface xdg_positioner_interface = {
955  "xdg_positioner", 3,
956  10, xdg_positioner_requests,
957  0, NULL,
958 };
959 static const struct wl_message xdg_surface_requests[] = {
960  { "destroy", "", xdg_shell_types + 0 },
961  { "get_toplevel", "n", xdg_shell_types + 7 },
962  { "get_popup", "n?oo", xdg_shell_types + 8 },
963  { "set_window_geometry", "iiii", xdg_shell_types + 0 },
964  { "ack_configure", "u", xdg_shell_types + 0 },
965 };
966 static const struct wl_message xdg_surface_events[] = {
967  { "configure", "u", xdg_shell_types + 0 },
968 };
969 const struct wl_interface xdg_surface_interface = {
970  "xdg_surface", 3,
971  5, xdg_surface_requests,
972  1, xdg_surface_events,
973 };
974 static const struct wl_message xdg_toplevel_requests[] = {
975  { "destroy", "", xdg_shell_types + 0 },
976  { "set_parent", "?o", xdg_shell_types + 11 },
977  { "set_title", "s", xdg_shell_types + 0 },
978  { "set_app_id", "s", xdg_shell_types + 0 },
979  { "show_window_menu", "ouii", xdg_shell_types + 12 },
980  { "move", "ou", xdg_shell_types + 16 },
981  { "resize", "ouu", xdg_shell_types + 18 },
982  { "set_max_size", "ii", xdg_shell_types + 0 },
983  { "set_min_size", "ii", xdg_shell_types + 0 },
984  { "set_maximized", "", xdg_shell_types + 0 },
985  { "unset_maximized", "", xdg_shell_types + 0 },
986  { "set_fullscreen", "?o", xdg_shell_types + 21 },
987  { "unset_fullscreen", "", xdg_shell_types + 0 },
988  { "set_minimized", "", xdg_shell_types + 0 },
989 };
990 static const struct wl_message xdg_toplevel_events[] = {
991  { "configure", "iia", xdg_shell_types + 0 },
992  { "close", "", xdg_shell_types + 0 },
993 };
994 const struct wl_interface xdg_toplevel_interface = {
995  "xdg_toplevel", 3,
996  14, xdg_toplevel_requests,
997  2, xdg_toplevel_events,
998 };
999 static const struct wl_message xdg_popup_requests[] = {
1000  { "destroy", "", xdg_shell_types + 0 },
1001  { "grab", "ou", xdg_shell_types + 22 },
1002  { "reposition", "3ou", xdg_shell_types + 24 },
1003 };
1004 static const struct wl_message xdg_popup_events[] = {
1005  { "configure", "iiii", xdg_shell_types + 0 },
1006  { "popup_done", "", xdg_shell_types + 0 },
1007  { "repositioned", "3u", xdg_shell_types + 0 },
1008 };
1009 const struct wl_interface xdg_popup_interface = {
1010  "xdg_popup", 3,
1011  3, xdg_popup_requests,
1012  3, xdg_popup_events,
1013 };
1014 #endif // ZAKERO_YETANI_IMPLEMENTATION
1015 // }}}
1016 // }}}
1017 
1022 namespace zakero
1023 {
1024  // {{{ Declaration
1025 
1026  class Yetani
1027  {
1028  public:
1029 #define X(name_, val_, mesg_) \
1030  static constexpr int name_ = val_;
1031  ZAKERO_YETANI__ERROR_DATA
1032 #undef X
1033 
1034  virtual ~Yetani() noexcept;
1035 
1036  // {{{ Type : Key
1037 
1038  enum struct KeyState
1039  { Released = 0
1040  , Pressed = 1
1041  , Repeat = 2
1042  };
1043 
1044  struct Key
1045  {
1046  uint32_t time;
1047  uint32_t code;
1049  };
1050 
1051  static constexpr uint32_t KeyModifier_Shift = 0x00000001;
1052  static constexpr uint32_t KeyModifier_CapsLock = 0x00000002;
1053  static constexpr uint32_t KeyModifier_Control = 0x00000004;
1054  static constexpr uint32_t KeyModifier_Alt = 0x00000008;
1055  static constexpr uint32_t KeyModifier_NumLock = 0x00000010;
1056  static constexpr uint32_t KeyModifier_Meta = 0x00000040;
1057 
1059  {
1060  uint32_t pressed = 0;
1061  uint32_t latched = 0;
1062  uint32_t locked = 0;
1063  uint32_t group = 0;
1064  };
1065 
1066  // }}}
1067  // {{{ Type : Point
1068 
1069  struct PointMm
1070  {
1071  uint32_t time;
1072  float x;
1073  float y;
1074 
1075  friend bool operator==(Yetani::PointMm&, Yetani::PointMm&) noexcept;
1076  };
1077 
1079  {
1080  uint32_t time;
1081  float x;
1082  float y;
1083 
1084  friend bool operator==(Yetani::PointPercent&, Yetani::PointPercent&) noexcept;
1085  };
1086 
1087  struct PointPixel
1088  {
1089  uint32_t time;
1090  int32_t x;
1091  int32_t y;
1092 
1093  friend bool operator==(Yetani::PointPixel&, Yetani::PointPixel&) noexcept;
1094  };
1095 
1096  // }}}
1097  // {{{ Type : Pointer Axis
1098 
1099  enum struct PointerAxisSource
1100  { Unknown
1101  , Continuous
1102  , Finger
1103  , Wheel
1104  , Wheel_Tilt
1105  };
1106 
1107  enum struct PointerAxisType
1108  { Unknown
1109  , Horizontal
1110  , Vertical
1111  };
1112 
1114  {
1115  uint32_t time;
1116  int32_t steps;
1117  float distance;
1120  };
1121 
1122  // }}}
1123  // {{{ Type : Pointer Button
1124 
1126  { Released = 0
1127  , Pressed = 1
1128  };
1129 
1131  {
1132  uint32_t code;
1134  };
1135 
1136  // }}}
1137  // {{{ Type : Size
1138 
1139  struct SizeMm
1140  {
1141  float width;
1142  float height;
1143 
1144  friend bool operator==(Yetani::SizeMm&, Yetani::SizeMm&) noexcept;
1145  };
1146 
1148  {
1149  float width;
1150  float height;
1151 
1152  friend bool operator==(Yetani::SizePercent&, Yetani::SizePercent&) noexcept;
1153  };
1154 
1155  struct SizePixel
1156  {
1157  int32_t width;
1158  int32_t height;
1159 
1160  friend bool operator==(Yetani::SizePixel&, Yetani::SizePixel&) noexcept;
1161  };
1162 
1163  // }}}
1164  // {{{ Connection
1165 
1166  static Yetani* connect() noexcept;
1167  static Yetani* connect(const std::string&) noexcept;
1168  static Yetani* connect(std::error_code&) noexcept;
1169  static Yetani* connect(const std::string&, std::error_code&) noexcept;
1170 
1171  // }}}
1172  // {{{ Cursor
1173 
1175  {
1177  wl_shm_format format = WL_SHM_FORMAT_ARGB8888;
1178  int32_t hotspot_x = 0;
1179  int32_t hotspot_y = 0;
1180  std::chrono::milliseconds time_per_frame = std::chrono::milliseconds(0);
1181  const std::vector<void*>& image_data;
1182  };
1183 
1184  // -------------------------------------------------- //
1185 
1186  std::error_code cursorCreate(const std::string&, const Yetani::CursorConfig&) noexcept;
1187  std::error_code cursorDestroy(const std::string&) noexcept;
1188 
1189  // }}}
1190  // {{{ Keyboard
1191 
1192  int32_t keyRepeatDelay() const noexcept;
1193  int32_t keyRepeatRate() const noexcept;
1194 
1195  // }}}
1196  // {{{ Output : Wayland
1197 
1198  struct Output
1199  {
1200  std::string make = "";
1201  std::string model = "";
1202  int32_t x = 0;
1203  int32_t y = 0;
1204  int32_t width = 0;
1205  int32_t height = 0;
1206  uint32_t physical_width_mm = 0;
1207  uint32_t physical_height_mm = 0;
1208  int32_t subpixel = 0;
1209  int32_t refresh_mHz = 0;
1210  int32_t scale_factor = 0;
1211  int32_t transform = 0;
1212  uint32_t flags = 0;
1213  float pixels_per_mm_horizontal = 0.0;
1214  float pixels_per_mm_vertical = 0.0;
1215  };
1216 
1217  // -------------------------------------------------- //
1218 
1219  using OutputId = uint32_t;
1220 
1221  using LambdaOutputId = std::function<void(const Yetani::OutputId)>;
1222 
1223  using VectorOutputId = std::vector<OutputId>;
1224 
1225  // -------------------------------------------------- //
1226 
1227  Yetani::Output output(const Yetani::OutputId) const noexcept;
1228  Yetani::VectorOutputId outputVector() const noexcept;
1229  static std::string outputSubpixelName(int32_t) noexcept;
1230  static std::string outputTransformName(int32_t) noexcept;
1231 
1232  Yetani::PointMm outputConvertToMm(const Yetani::OutputId, const Yetani::PointPixel&) const noexcept;
1233  Yetani::PointPercent outputConvertToPercent(const Yetani::OutputId, const Yetani::PointPixel&) const noexcept;
1234  Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointMm&) const noexcept;
1235  Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointPercent&) const noexcept;
1236 
1237  Yetani::SizeMm outputConvertToMm(const Yetani::OutputId, const Yetani::SizePixel&) const noexcept;
1238  Yetani::SizePercent outputConvertToPercent(const Yetani::OutputId, const Yetani::SizePixel&) const noexcept;
1239  Yetani::SizePixel outputConvertToPixel(const Yetani::OutputId, const Yetani::SizeMm&) const noexcept;
1240  Yetani::SizePixel outputConvertToPixel(const Yetani::OutputId, const Yetani::SizePercent&) const noexcept;
1241 
1242  void outputOnAdd(Yetani::LambdaOutputId) noexcept;
1243  void outputOnChange(Yetani::LambdaOutputId) noexcept;
1244  void outputOnRemove(Yetani::LambdaOutputId) noexcept;
1245 
1246  // }}}
1247  // {{{ Output : Xdg
1248 
1249  /* Future
1250  struct XdgOutput
1251  {
1252  std::string xdg_name;
1253  std::string xdg_description;
1254  int32_t xdg_logical_x;
1255  int32_t xdg_logical_y;
1256  int32_t xdg_logical_width;
1257  int32_t xdg_logical_height;
1258  };
1259 
1260  using MapXdgOutputData = std::unordered_map<OutputId, XdgOutput>;
1261 
1262  // -------------------------------------------------- //
1263 
1264  const MapOutputIdXdgOutput& xdgOutputMap() const noexcept;
1265  */
1266 
1267  // }}}
1268  // {{{ Shared Memory
1269 
1270  using VectorShmFormat = std::vector<wl_shm_format>;
1271 
1272  // -------------------------------------------------- //
1273 
1274  const Yetani::VectorShmFormat& shmFormatAvailable() const noexcept;
1275  static uint8_t shmFormatBytesPerPixel(const wl_shm_format) noexcept;
1276  static std::string shmFormatDescription(const wl_shm_format) noexcept;
1277  static std::string shmFormatName(const wl_shm_format) noexcept;
1278 
1279  // }}}
1280  // {{{ Window
1281 
1282  enum struct WindowDecorations
1283  { Client_Side
1284  , Server_Side
1285  };
1286 
1287  enum struct WindowMode
1288  { Normal
1289  , Fullscreen
1290  , Maximized
1291  };
1292 
1293  // -------------------------------------------------- //
1294 
1295  using Lambda = std::function<void()>;
1296  using LambdaKey = std::function<void(const Yetani::Key&, const Yetani::KeyModifier&)>;
1297  using LambdaAxis = std::function<void(const Yetani::PointerAxis&, const Yetani::KeyModifier&)>;
1298  using LambdaButtonMm = std::function<void(const Yetani::PointerButton&, const Yetani::PointMm&, const Yetani::KeyModifier&)>;
1299  using LambdaButtonPercent = std::function<void(const Yetani::PointerButton&, const Yetani::PointPercent&, const Yetani::KeyModifier&)>;
1300  using LambdaButtonPixel = std::function<void(const Yetani::PointerButton&, const Yetani::PointPixel&, const Yetani::KeyModifier&)>;
1301  using LambdaPointMm = std::function<void(const Yetani::PointMm&, const Yetani::KeyModifier&)>;
1302  using LambdaPointPercent = std::function<void(const Yetani::PointPercent&, const Yetani::KeyModifier&)>;
1303  using LambdaPointPixel = std::function<void(const Yetani::PointPixel&, const Yetani::KeyModifier&)>;
1304  using LambdaBool = std::function<void(bool)>;
1306  using LambdaWindowMode = std::function<void(Yetani::WindowMode)>;
1307  using LambdaSizeMm = std::function<void(const Yetani::SizeMm&)>;
1308  using LambdaSizePercent = std::function<void(const Yetani::SizePercent&)>;
1309  using LambdaSizePixel = std::function<void(const Yetani::SizePixel&)>;
1310 
1311  // -------------------------------------------------- //
1312 
1313  class Window
1314  {
1315  public:
1316  Window(void*);
1317  virtual ~Window();
1318 
1319  // {{{ Configuration
1320 
1321  void classSet(const std::string&) noexcept;
1322  void titleSet(const std::string&) noexcept;
1323 
1324  // }}}
1325  // {{{ Decorations
1326 
1327  std::error_code decorationsSet(const Yetani::WindowDecorations) noexcept;
1329 
1330  // }}}
1331  // {{{ Size
1332 
1333  std::error_code sizeSet(const Yetani::SizeMm&) noexcept;
1334  std::error_code sizeSet(const Yetani::SizePercent&) noexcept;
1335  std::error_code sizeSet(const Yetani::SizePixel&) noexcept;
1336  std::error_code sizeSetMinMax(const Yetani::SizeMm&, const Yetani::SizeMm&) noexcept;
1337  std::error_code sizeSetMinMax(const Yetani::SizePercent&, const Yetani::SizePercent&) noexcept;
1338  std::error_code sizeSetMinMax(const Yetani::SizePixel&, const Yetani::SizePixel&) noexcept;
1339  void sizeOnChange(Yetani::LambdaSizeMm) noexcept;
1340  void sizeOnChange(Yetani::LambdaSizePercent) noexcept;
1341  void sizeOnChange(Yetani::LambdaSizePixel) noexcept;
1342 
1343  // }}}
1344  // {{{ Window Mode
1345 
1346  Yetani::WindowMode windowMode() noexcept;
1347  bool windowModeIs(const Yetani::WindowMode) noexcept;
1348  void windowModeSet(const Yetani::WindowMode) noexcept;
1350 
1351  void minimize() noexcept;
1352 
1353  // }}}
1354  // {{{ Rendering
1355 
1356  std::error_code imageNext(uint8_t*&, Yetani::SizePixel&) noexcept;
1357  void imagePresent() noexcept;
1358  uint32_t time() const noexcept;
1359  uint8_t bytesPerPixel() const noexcept;
1360 
1361  // }}}
1362  // {{{ Conversion
1363 
1364  Yetani::PointMm convertToMm(const Yetani::PointPixel&) const noexcept;
1366  Yetani::PointPixel convertToPixel(const Yetani::PointMm&) const noexcept;
1368 
1369  Yetani::SizeMm convertToMm(const Yetani::SizePixel&) const noexcept;
1371  Yetani::SizePixel convertToPixel(const Yetani::SizeMm&) const noexcept;
1372  Yetani::SizePixel convertToPixel(const Yetani::SizePercent&) const noexcept;
1373 
1374  // }}}
1375  // {{{ Cursor
1376 
1377  std::error_code cursorUse(const std::string&) noexcept;
1378  void cursorHide() noexcept;
1379  void cursorShow() noexcept;
1380 
1381  // }}}
1382  // {{{ Keyboard
1383 
1384  void keyboardOnEnter(Yetani::Lambda) noexcept;
1385  void keyboardOnLeave(Yetani::Lambda) noexcept;
1386  void keyboardOnKey(Yetani::LambdaKey) noexcept;
1387 
1388  // }}}
1389  // {{{ Pointer
1390 
1391  void pointerOnAxis(Yetani::LambdaAxis) noexcept;
1392  void pointerOnButton(Yetani::LambdaButtonMm) noexcept;
1395  void pointerOnEnter(Yetani::LambdaPointMm) noexcept;
1398  void pointerOnLeave(Yetani::Lambda) noexcept;
1399  void pointerOnMotion(Yetani::LambdaPointMm) noexcept;
1402 
1403  // Not Used? Or Future?
1404  void pointerOnAxisSource(Yetani::Lambda) noexcept;
1405  void pointerOnAxisStop(Yetani::Lambda) noexcept;
1406  void pointerOnAxisDiscrete(Yetani::Lambda) noexcept;
1407 
1408  // }}}
1409  // {{{ Events
1410 
1411  void onCloseRequest(Yetani::Lambda) noexcept;
1412  void onFocusChange(Yetani::LambdaBool) noexcept;
1413 
1414  // }}}
1415 
1416  struct Memory
1417  {
1420  };
1421 
1422  private:
1423  Yetani* yetani;
1424  struct wl_buffer* wl_buffer;
1425  struct wl_surface* wl_surface;
1426  struct xdg_surface* xdg_surface;
1427  struct xdg_toplevel* xdg_toplevel;
1428  struct zxdg_toplevel_decoration_v1* xdg_decoration;
1429  Yetani::Window::Memory window_memory;
1430  wl_shm_format pixel_format;
1431 
1432  Window(const Window&) = delete;
1433  Window& operator=(const Window&) = delete;
1434  };
1435 
1436  // -------------------------------------------------- //
1437 
1438  static constexpr wl_shm_format SHM_FORMAT_DEFAULT = WL_SHM_FORMAT_XRGB8888;
1439 
1440  // -------------------------------------------------- //
1441 
1442  Yetani::Window* windowCreate(const Yetani::SizeMm&, std::error_code&) noexcept;
1443  Yetani::Window* windowCreate(const Yetani::SizeMm&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1444  Yetani::Window* windowCreate(const Yetani::SizeMm&, const wl_shm_format, std::error_code&) noexcept;
1445  Yetani::Window* windowCreate(const Yetani::SizePercent&, std::error_code&) noexcept;
1446  Yetani::Window* windowCreate(const Yetani::SizePercent&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1447  Yetani::Window* windowCreate(const Yetani::SizePercent&, const wl_shm_format, std::error_code&) noexcept;
1448  Yetani::Window* windowCreate(const Yetani::SizePixel&, std::error_code&) noexcept;
1449  Yetani::Window* windowCreate(const Yetani::SizePixel&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1450  Yetani::Window* windowCreate(const Yetani::SizePixel&, const wl_shm_format, std::error_code&) noexcept;
1451 
1452  // }}}
1453 
1454  private:
1455  static constexpr uint32_t Size_Max = (uint32_t)std::numeric_limits<int32_t>::max();
1456 
1457  Yetani() noexcept;
1458 
1459  // {{{ Type
1460 
1461  using VectorWlSurface = std::vector<struct wl_surface*>;
1462 
1463  // }}}
1464  // {{{ Connection
1465 
1466  void disconnect() noexcept;
1467 
1468  // }}}
1469  // {{{ Cursor
1470 
1471  struct Cursor
1472  {
1473  struct wl_surface* wl_surface = nullptr;
1474  std::vector<::wl_buffer*> buffer_vector = {};
1475  wl_shm_format format = WL_SHM_FORMAT_ARGB8888;
1476  int64_t next_frame_time = 0;
1477  size_t buffer_index = 0;
1478  uint32_t time_per_frame = 0;
1479  int32_t width = 0;
1480  int32_t height = 0;
1481  int32_t hotspot_x = 0;
1482  int32_t hotspot_y = 0;
1483  };
1484 
1485  using MapStringCursor = std::unordered_map<std::string, Yetani::Cursor>;
1486 
1487  MapStringCursor cursor_map;
1488 
1489  // -------------------------------------------------- //
1490 
1491  struct CursorSurface
1492  {
1493  struct wl_pointer* wl_pointer;
1494  struct wl_surface* wl_surface;
1495  uint32_t serial;
1496  int32_t hotspot_x;
1497  int32_t hotspot_y;
1498  bool is_visible;
1499  };
1500 
1501  using MapCursorSurface = std::unordered_map<struct wl_surface*, Yetani::CursorSurface>;
1502 
1503  MapCursorSurface cursor_surface_map;
1504 
1505  // -------------------------------------------------- //
1506 
1507  zakero::MemoryPool cursor_memory_pool;
1508  mutable std::mutex cursor_mutex;
1509  struct wl_shm_pool* cursor_shm_pool;
1510  struct wl_pointer* cursor_pointer;
1511 
1512  // -------------------------------------------------- //
1513 
1514  void cursorAnimate() noexcept;
1515  std::error_code cursorCreateCursor(const std::string&, const Yetani::CursorConfig&) noexcept;
1516  void cursorEnter(struct wl_pointer*, uint32_t, struct wl_surface*) noexcept;
1517  void cursorLeave(struct wl_surface*) noexcept;
1518  void cursorHide(struct wl_surface*) noexcept;
1519  void cursorShow(struct wl_surface*) noexcept;
1520  bool cursorIsHidden(struct wl_surface*) const noexcept;
1521  void cursorSetup() noexcept;
1522  void cursorTeardown() noexcept;
1523  std::error_code cursorAttach(const std::string&, struct wl_surface*) noexcept;
1524  std::error_code cursorDetach(struct wl_surface*) noexcept;
1525 
1526  // }}}
1527  // {{{ Event Loop
1528 
1529  std::jthread event_loop;
1530  std::atomic<bool> event_loop_is_running;
1531 
1532  // -------------------------------------------------- //
1533 
1534  void eventLoopStart() noexcept;
1535  static void eventLoop(std::stop_token, Yetani*) noexcept;
1536 
1537  // }}}
1538  // {{{ Wayland
1539 
1540  struct wl_compositor* compositor;
1541  struct wl_display* display;
1542  struct wl_registry* registry;
1543  struct wl_shm* shm;
1544  Yetani::VectorShmFormat shm_format_vector;
1545 
1546  // }}}
1547  // {{{ Wayland : Seat
1548 
1549  struct Seat
1550  {
1551  struct wl_keyboard* wl_keyboard = nullptr;
1552  struct wl_pointer* wl_pointer = nullptr;
1553  struct wl_touch* wl_touch = nullptr;
1554  std::string name = "";
1555  uint32_t version = 0;
1556  };
1557 
1558  using MapSeat = std::map<struct wl_seat*, Seat>;
1559  using MapIdWlSeat = std::map<uint32_t, struct wl_seat*>;
1560 
1561  Yetani::MapSeat seat_map;
1562  Yetani::MapIdWlSeat id_to_seat;
1563 
1564  // -------------------------------------------------- //
1565 
1566  struct wl_seat* seat;
1567 
1568  // -------------------------------------------------- //
1569 
1570  void seatDestroy(struct wl_seat*&) noexcept;
1571 
1572  // }}}
1573  // {{{ Wayland : Seat : Keyboard
1574 
1575  struct KeyRepeatData
1576  {
1577  std::chrono::time_point<std::chrono::steady_clock> trigger_time = {};
1578  uint32_t base_time = 0;
1579  };
1580 
1581  using KeyRepeatMap = std::map<uint32_t, Yetani::KeyRepeatData>;
1582 
1583  // -------------------------------------------------- //
1584 
1585  struct KeyboardEvent
1586  {
1587  Yetani::Lambda on_enter = {};
1588  Yetani::Lambda on_leave = {};
1589  Yetani::LambdaKey on_key = {};
1590  };
1591 
1592  using MapKeyboardEvent = std::unordered_map<struct wl_surface*, Yetani::KeyboardEvent>;
1593 
1594  // -------------------------------------------------- //
1595 
1596  struct Keyboard
1597  {
1598  struct wl_surface* wl_surface = nullptr;
1599  Yetani::KeyboardEvent* event = nullptr;
1600  Yetani::MapKeyboardEvent event_map = {};
1601  Yetani::KeyModifier modifier = {};
1602  Yetani::KeyRepeatMap repeat_map = {};
1603  char* keymap = nullptr;
1604  uint32_t keymap_size = 0;
1605  int32_t repeat_delay = 0;
1606  int32_t repeat_rate = 0;
1607  };
1608 
1609  Yetani::Keyboard keyboard;
1610 
1611  // -------------------------------------------------- //
1612 
1613  static void keyboardDestroy(Yetani::Keyboard&) noexcept;
1614  static void keyboardRepeat(Yetani::Keyboard&) noexcept;
1615  static void keyboardRepeatAdd(Yetani::Keyboard&, uint32_t, uint32_t) noexcept;
1616  static void keyboardRepeatReleaseAll(Yetani::Keyboard&) noexcept;
1617  static void keyboardRepeatRemove(Yetani::Keyboard&, uint32_t) noexcept;
1618 
1619  // }}}
1620  // {{{ Wayland : Seat : Pointer
1621 
1622  struct PointerEvent
1623  {
1624  Yetani::LambdaAxis on_axis = {};
1625  Yetani::Lambda on_axis_discrete = {};
1626  Yetani::Lambda on_axis_source = {};
1627  Yetani::Lambda on_axis_stop = {};
1628  Yetani::LambdaButtonMm on_button_mm = {};
1629  Yetani::LambdaButtonPercent on_button_percent = {};
1630  Yetani::LambdaButtonPixel on_button_pixel = {};
1631  Yetani::LambdaPointMm on_enter_mm = {};
1632  Yetani::LambdaPointPercent on_enter_percent = {};
1633  Yetani::LambdaPointPixel on_enter_pixel = {};
1634  Yetani::Lambda on_leave = {};
1635  Yetani::LambdaPointMm on_motion_mm = {};
1636  Yetani::LambdaPointPercent on_motion_percent = {};
1637  Yetani::LambdaPointPixel on_motion_pixel = {};
1638  };
1639 
1640  using MapPointerEvent = std::unordered_map<struct wl_surface*, Yetani::PointerEvent>;
1641 
1642  // -------------------------------------------------- //
1643 
1644  struct Pointer
1645  {
1646  // --- Common --- //
1647  Yetani* yetani = nullptr;
1648  struct wl_surface* wl_surface = nullptr;
1649  struct wl_pointer* wl_pointer = nullptr;
1650  Yetani::PointerEvent* event = nullptr;
1651  Yetani::MapPointerEvent event_map = {};
1652 
1653  // --- Processed Data --- //
1654  Yetani::PointMm point_mm = {};
1655  Yetani::PointPercent point_percent = {};
1656  Yetani::PointPixel point_pixel = {};
1657 
1658  // --- Axis --- //
1659  Yetani::PointerAxis axis = {};
1660 
1661  // --- Button --- //
1662  Yetani::PointerButton button = {};
1663  uint32_t button_event_code = 0;
1664  bool button_is_pressed = false;
1665  uint32_t button_time = {};
1666 
1667  // --- Enter --- //
1668  struct wl_surface* enter_surface = nullptr;
1669  Yetani::PointPixel enter_point = {};
1670  uint32_t enter_serial = 0;
1671 
1672  // --- Leave --- //
1673  struct wl_surface* leave_surface = nullptr;
1674 
1675  // --- Motion --- //
1676  Yetani::PointPixel motion_point = {};
1677  };
1678 
1679  Yetani::Pointer pointer;
1680 
1681  // -------------------------------------------------- //
1682 
1683  static void pointerClear(struct Pointer&) noexcept;
1684 
1685  // }}}
1686  // {{{ Wayland : Output
1687 
1688  enum struct OutputState
1689  { Done
1690  , Added
1691  , Changed
1692  };
1693 
1694  // -------------------------------------------------- //
1695 
1696  using VectorWlOutput = std::vector<struct wl_output*>;
1697 
1698  using MapWlOutputOutputState = std::unordered_map<struct wl_output*, Yetani::OutputState>;
1699  using MapOutputIdWlOutput = std::unordered_map<Yetani::OutputId, struct wl_output*>;
1700  using MapWlOutputOutputId = std::unordered_map<struct wl_output*, Yetani::OutputId>;
1701  using MapWlSurfaceVectorWlOutput = std::unordered_map<struct wl_surface*, Yetani::VectorWlOutput>;
1702  using MapWlOutputOutput = std::unordered_map<struct wl_output*, Output>;
1703 
1704  // -------------------------------------------------- //
1705 
1706  struct OutputData
1707  {
1708  Yetani::MapWlSurfaceVectorWlOutput surface_output_map = {};
1709  Yetani::MapOutputIdWlOutput outputid_to_wloutput = {};
1710  Yetani::MapWlOutputOutput output_map = {};
1711  Yetani::MapWlOutputOutputId wloutput_to_outputid = {};
1712  mutable std::mutex mutex = {};
1713  };
1714 
1715  Yetani::OutputData output_data;
1716 
1717  // -------------------------------------------------- //
1718 
1719  Yetani::LambdaOutputId on_output_add;
1720  Yetani::LambdaOutputId on_output_change;
1721  Yetani::LambdaOutputId on_output_remove;
1722 
1723  Yetani::MapWlOutputOutput output_changes_map;
1724  Yetani::MapWlOutputOutputState output_state_map;
1725 
1726  Yetani::VectorWlSurface output_notify_surface_vector;
1727 
1728  // -------------------------------------------------- //
1729 
1730  void convertPixel(struct wl_surface*, const int32_t, const int32_t, float&, float&, float&, float&) const noexcept;
1731 
1732  std::pair<float, float> convertPixelToMm(const Yetani::Output&, int32_t, int32_t) const noexcept;
1733  std::pair<float, float> convertPixelToPercent(const Yetani::Output&, int32_t, int32_t) const noexcept;
1734  std::pair<int32_t, int32_t> convertMmToPixel(const Yetani::Output&, float, float) const noexcept;
1735  std::pair<int32_t, int32_t> convertPercentToPixel(const Yetani::Output&, float, float) const noexcept;
1736 
1737  static void outputNotifySurface(Yetani*, struct wl_output*, struct wl_surface*) noexcept;
1738 
1739  // }}}
1740  // {{{ Wayland : Buffer
1741 
1742  struct SurfaceSize;
1743 
1744  struct BufferData
1745  {
1746  MemoryPool* memory_pool = nullptr;
1747  off_t offset = 0;
1748  };
1749 
1750  using MapBufferData = std::unordered_map<struct wl_buffer*, BufferData>;
1751 
1752  // -------------------------------------------------- //
1753 
1754  struct Buffer
1755  {
1756  MapBufferData map = {};
1757  std::mutex mutex = {};
1758  };
1759 
1760  Buffer buffer;
1761 
1762  // -------------------------------------------------- //
1763 
1764  static wl_buffer* bufferCreate(Yetani::SurfaceSize&, Yetani::Window::Memory*, Yetani::Buffer*) noexcept;
1765  static void bufferDestroy(struct wl_buffer*&) noexcept;
1766 
1767  // }}}
1768  // {{{ Wayland : Surface
1769 
1770  struct SurfaceEvent
1771  {
1772  Yetani::LambdaSizeMm on_size_mm_change = {};
1773  Yetani::LambdaSizePercent on_size_percent_change = {};
1774  Yetani::LambdaSizePixel on_size_pixel_change = {};
1775  };
1776 
1777  using MapSurfaceEvent = std::map<struct wl_surface*, Yetani::SurfaceEvent>;
1778 
1779  MapSurfaceEvent surface_event_map;
1780 
1781  // -------------------------------------------------- //
1782 
1783  enum struct SizeUnit
1784  { Millimeter
1785  , Percent
1786  , Pixel
1787  };
1788 
1789  // This is the data that needs to be locked from resizing
1790  // Use mainly by XdgSurface related methods
1791  struct SurfaceExtent
1792  {
1793  Yetani::SizeUnit preferred_unit = {};
1794  Yetani::SizeMm preferred_mm = {};
1795  Yetani::SizePercent preferred_percent = {};
1796  Yetani::SizeMm size_mm = {};
1797  Yetani::SizePercent size_percent = {};
1798  Yetani::SizePixel size_pixel = {};
1799  Yetani::SizePixel size_pixel_max = {};
1800  Yetani::SizePixel size_pixel_min = {};
1801  };
1802 
1803  using MapSurfaceExtent = std::unordered_map<struct wl_surface*, Yetani::SurfaceExtent>;
1804 
1805  MapSurfaceExtent surface_extent_map;
1806  std::mutex surface_extent_mutex; // For surface adding and removing
1807 
1808  // -------------------------------------------------- //
1809 
1810  struct SurfaceFrame
1811  {
1812  struct wl_surface* wl_surface = nullptr;
1813  std::atomic<wl_buffer*> buffer_next = {};
1814  uint32_t width = 0;
1815  uint32_t height = 0;
1816  uint32_t time_ms = 0;
1817  };
1818 
1819  using MapSurfaceFrame = std::unordered_map<struct wl_surface*, Yetani::SurfaceFrame>;
1820 
1821  MapSurfaceFrame surface_frame_map;
1822 
1823  // -------------------------------------------------- //
1824 
1825  struct SurfaceSize
1826  {
1827  int32_t width;
1828  int32_t height;
1829  int32_t stride;
1830  uint32_t in_bytes;
1831  wl_shm_format pixel_format;
1832  uint8_t bytes_per_pixel;
1833  };
1834 
1835  using MapSurfaceSize = std::unordered_map<struct wl_surface*, Yetani::SurfaceSize>;
1836 
1837  MapSurfaceSize surface_size_map;
1838 
1839  // -------------------------------------------------- //
1840 
1841  using MapSurfaceResizeMutex = std::unordered_map<struct wl_surface*, std::mutex>;
1842 
1843  MapSurfaceResizeMutex surface_resize_mutex_map;
1844 
1845  // -------------------------------------------------- //
1846 
1847  static void surfaceCalculateSize(Yetani*, struct wl_surface*, const Yetani::SizePixel&) noexcept;
1848  static struct wl_surface* surfaceCreate(Yetani*, const wl_shm_format, const Yetani::SizePixel&, Yetani::Window::Memory&) noexcept;
1849  static void surfaceDestroy(Yetani*, struct wl_surface*&) noexcept;
1850 
1851  // }}}
1852  // {{{ Window
1853 
1854  struct WindowData
1855  {
1856  Yetani* yetani;
1857  struct wl_shm* wl_shm;
1858  struct wl_output* wl_output;
1859  std::string file_name;
1860  Yetani::SizeMm size_mm;
1861  Yetani::SizePercent size_percent;
1862  Yetani::SizePixel size_pixel;
1863  Yetani::SizeUnit size_unit;
1864  wl_shm_format pixel_format;
1865  std::error_code error;
1866  };
1867 
1868  // -------------------------------------------------- //
1869 
1870  Yetani::Window* windowCreate(const Yetani::SizeUnit, const Yetani::SizeMm&, const Yetani::SizePercent&, const Yetani::SizePixel&, const wl_shm_format, std::error_code&) noexcept;
1871  void windowDataInit(Yetani::WindowData&) noexcept;
1872  void windowDataInitOutput(Yetani::WindowData&) noexcept;
1873  void windowInitMemory(Yetani::WindowData&, Yetani::Window::Memory&) noexcept;
1874  void windowInitOutput(Yetani::WindowData&, struct wl_surface*) noexcept;
1875  void windowEraseMemory(Yetani::Window::Memory&) noexcept;
1876  void windowEraseOutput(struct wl_surface*) noexcept;
1877  void windowEraseSurfaceExtent(struct wl_surface*) noexcept;
1878 
1879  // }}}
1880  // {{{ Utility
1881 
1882  std::vector<Yetani::Window*> window_vector;
1883  std::mutex window_vector_mutex;
1884 
1885  // -------------------------------------------------- //
1886 
1887  void windowAdd(Yetani::Window*) noexcept;
1888  void windowRemove(Yetani::Window*) noexcept;
1889 
1890  // }}}
1891  // {{{ XDG
1892 
1893  enum XdgState : int32_t
1894  { Unknown = 0
1895  , Toplevel_Active = 1
1896  , Toplevel_Attach_Buffer = 2
1897  , Toplevel_Resizing = 3
1898  , Toplevel_Window_Fullscreen = 4
1899  , Toplevel_Window_Maximized = 5
1900  , Toplevel_Window_Normal = 6
1901  , Toplevel_Decoration = 7
1902  };
1903 
1904  using VectorXdgStateChange = std::vector<int32_t>;
1905  using MapXdgStateChange = std::unordered_map<struct xdg_surface*, Yetani::VectorXdgStateChange>;
1906 
1907  Yetani::MapXdgStateChange xdg_state_change_map;
1908  std::mutex xdg_state_change_mutex;
1909 
1910  // -------------------------------------------------- //
1911 
1912  struct xdg_wm_base* xdg_wm_base;
1913 
1914  // -------------------------------------------------- //
1915 
1916  static Yetani::WindowMode toWindowMode(const Yetani::XdgState) noexcept;
1917  static Yetani::XdgState toXdgState(const Yetani::WindowMode) noexcept;
1918 
1919  // }}}
1920  // {{{ XDG : Surface
1921 
1922  struct XdgSurface
1923  {
1924  Yetani* yetani = nullptr;
1925  struct wl_surface* wl_surface = nullptr;
1926  };
1927 
1928  using MapXdgSurface = std::unordered_map<struct wl_surface*, Yetani::XdgSurface>;
1929 
1930  Yetani::MapXdgSurface xdg_surface_map;
1931 
1932  // -------------------------------------------------- //
1933 
1934  struct xdg_surface* xdgSurfaceCreate(struct wl_surface*) noexcept;
1935  void xdgSurfaceDestroy(struct wl_surface*, struct xdg_surface*&) noexcept;
1936  void xdgSurfaceSetExtent(struct wl_surface*, const Yetani::SizeUnit&, const Yetani::SizeMm&, const Yetani::SizePercent&, const Yetani::SizePixel&) noexcept;
1937 
1938  // }}}
1939  // {{{ XDG : Toplevel
1940 
1941  struct XdgToplevel
1942  {
1943  Yetani::VectorXdgStateChange* state_change = nullptr;
1944  Yetani::Lambda close_request_lambda = {};
1945  Yetani::LambdaBool is_active_lambda = {};
1946  bool is_active = false;
1947  Yetani::XdgState window_state = XdgState::Unknown;
1948  Yetani::LambdaWindowMode window_state_lambda = {};
1949  Yetani::SizePixel previous_size = {};
1950  struct xdg_toplevel* xdg_toplevel = nullptr;
1951  };
1952 
1953  using MapXdgToplevel = std::unordered_map<struct xdg_surface*, Yetani::XdgToplevel>;
1954 
1955  MapXdgToplevel xdg_toplevel_map;
1956 
1957  // -------------------------------------------------- //
1958 
1959  struct xdg_toplevel* xdgToplevelCreate(struct xdg_surface*) noexcept;
1960  void xdgToplevelDestroy(struct xdg_surface*, struct xdg_toplevel*&) noexcept;
1961  static void xdgToplevelSizeChange(Yetani*, struct wl_surface*, const Yetani::SizePixel&) noexcept;
1962  static void xdgToplevelSizeMinMaxChange(Yetani*, struct xdg_toplevel*, struct wl_surface*, const Yetani::SizePixel&, const Yetani::SizePixel&) noexcept;
1963  static void xdgToplevelWindowChange(Yetani*, struct wl_surface*, Yetani::XdgToplevel&, const Yetani::XdgState, const Yetani::SizePixel&) noexcept;
1964 
1965  // }}}
1966  // {{{ XDG : Decoration Manager (Unstable)
1967 
1968  struct XdgDecoration
1969  {
1970  Yetani::VectorXdgStateChange* state_change = nullptr;
1971  Yetani::LambdaWindowDecorations lambda = {};
1972  uint32_t state = 0;
1973  bool is_present = false;
1974  //struct zxdg_toplevel_decoration_v1* xdg_decoration;
1975  };
1976 
1977  using MapXdgDecoration = std::unordered_map<struct xdg_surface*, Yetani::XdgDecoration>;
1978 
1979  MapXdgDecoration xdg_decoration_map;
1980 
1981  // -------------------------------------------------- //
1982 
1983  struct zxdg_decoration_manager_v1* decoration_manager;
1984 
1985  // -------------------------------------------------- //
1986 
1987  struct zxdg_toplevel_decoration_v1* xdgDecorationCreate(struct xdg_surface*, struct xdg_toplevel*) noexcept;
1988  void xdgDecorationDestroy(struct xdg_surface*, struct xdg_toplevel*, struct zxdg_toplevel_decoration_v1*&) noexcept;
1989  static void xdgDecorationChange(Yetani::XdgDecoration&, const uint32_t) noexcept;
1990 
1991  // }}}
1992  // {{{ Listener Handlers : Wayland
1993 
1994  static struct wl_buffer_listener buffer_listener;
1995  static struct wl_callback_listener frame_callback_listener;
1996  static struct wl_keyboard_listener keyboard_listener;
1997  static struct wl_output_listener output_listener;
1998  static struct wl_pointer_listener pointer_listener;
1999  static struct wl_registry_listener registry_listener;
2000  static struct wl_seat_listener seat_listener;
2001  static struct wl_shm_listener shm_listener;
2002  static struct wl_surface_listener surface_listener;
2003 
2004  // -------------------------------------------------- //
2005 
2006  static void handlerBufferRelease(void*, struct wl_buffer*) noexcept;
2007 
2008  static void handlerKeyboardEnter(void*, struct wl_keyboard*, uint32_t, struct wl_surface*, struct wl_array*) noexcept;
2009  static void handlerKeyboardKey(void*, struct wl_keyboard*, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
2010  static void handlerKeyboardKeymap(void*, struct wl_keyboard*, uint32_t, int32_t, uint32_t) noexcept;
2011  static void handlerKeyboardLeave(void*, struct wl_keyboard*, uint32_t, struct wl_surface*) noexcept;
2012  static void handlerKeyboardModifiers(void*, struct wl_keyboard*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
2013  static void handlerKeyboardRepeatInfo(void*, struct wl_keyboard*, int32_t, int32_t) noexcept;
2014 
2015  static void handlerOutputDone(void*, struct wl_output*) noexcept;
2016  static void handlerOutputGeometry(void*, struct wl_output*, int32_t, int32_t, int32_t, int32_t, int32_t, const char*, const char*, int32_t) noexcept;
2017  static void handlerOutputMode(void*, struct wl_output*, uint32_t, int32_t, int32_t, int32_t) noexcept;
2018  static void handlerOutputScale(void*, struct wl_output*, int32_t) noexcept;
2019  static void handlerPointerAxis(void*, struct wl_pointer*, uint32_t, uint32_t, wl_fixed_t) noexcept;
2020  static void handlerPointerAxisDiscrete(void*, struct wl_pointer*, uint32_t, int32_t) noexcept;
2021  static void handlerPointerAxisSource(void*, struct wl_pointer*, uint32_t) noexcept;
2022  static void handlerPointerAxisStop(void*, struct wl_pointer*, uint32_t, uint32_t) noexcept;
2023  static void handlerPointerButton(void*, struct wl_pointer*, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
2024  static void handlerPointerEnter(void*, struct wl_pointer*, uint32_t, struct wl_surface*, wl_fixed_t, wl_fixed_t) noexcept;
2025  static void handlerPointerFrame(void*, struct wl_pointer*) noexcept;
2026  static void handlerPointerLeave(void*, struct wl_pointer*, uint32_t, struct wl_surface*) noexcept;
2027  static void handlerPointerMotion(void*, struct wl_pointer*, uint32_t, wl_fixed_t, wl_fixed_t) noexcept;
2028  static void handlerRegistryGlobal(void*, struct wl_registry*, uint32_t, const char*, uint32_t) noexcept;
2029  static void handlerRegistryRemove(void*, struct wl_registry*, uint32_t) noexcept;
2030  static void handlerSeatCapabilities(void*, struct wl_seat*, uint32_t) noexcept;
2031  static void handlerSeatName(void*, struct wl_seat*, const char*) noexcept;
2032  static void handlerShmFormat(void*, struct wl_shm*, uint32_t) noexcept;
2033  static void handlerSurfaceEnter(void*, struct wl_surface*, struct wl_output*) noexcept;
2034  static void handlerSurfaceLeave(void*, struct wl_surface*, struct wl_output*) noexcept;
2035  static void handlerSwapBuffers(void*, struct wl_callback*, uint32_t) noexcept;
2036 
2037  // }}}
2038  // {{{ Listener Handlers : Wayland Unstable
2039  // }}}
2040  // {{{ Listener Handlers : XDG
2041 
2042  static struct xdg_wm_base_listener xdg_wm_base_listener;
2043  static struct xdg_surface_listener xdg_surface_listener;
2044  static struct xdg_toplevel_listener xdg_toplevel_listener;
2045 
2046  // -------------------------------------------------- //
2047 
2048  static void handlerXdgSurfaceConfigure(void*, struct xdg_surface*, uint32_t) noexcept;
2049  static void handlerXdgToplevelClose(void*, struct xdg_toplevel*) noexcept;
2050  static void handlerXdgToplevelConfigure(void*, struct xdg_toplevel*, int32_t, int32_t, struct wl_array*) noexcept;
2051  static void handlerXdgWmBasePing(void*, struct xdg_wm_base*, uint32_t) noexcept;
2052 
2053  // }}}
2054  // {{{ Listener Handlers : XDG Unstable
2055 
2056  static struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener;
2057 
2058  // -------------------------------------------------- //
2059 
2060  static void handlerXdgToplevelDecorationConfigure(void*, struct zxdg_toplevel_decoration_v1*, uint32_t mode) noexcept;
2061 
2062  // }}}
2063 
2064  Yetani(const Yetani&) = delete;
2065  Yetani& operator=(const Yetani&) = delete;
2066  }; // class Yetani
2067 
2068  // }}}
2069  // {{{ Convenience
2070 
2071  std::string to_string(const wl_shm_format&) noexcept;
2072  std::string to_string(const std::error_code&) noexcept;
2073  std::string to_string(const Yetani::Key&) noexcept;
2074  std::string to_string(const Yetani::KeyModifier&) noexcept;
2075  std::string to_string(const Yetani::KeyState&) noexcept;
2076  std::string to_string(const Yetani::Output&) noexcept;
2077  std::string to_string(const Yetani::PointMm&) noexcept;
2078  std::string to_string(const Yetani::PointPercent&) noexcept;
2079  std::string to_string(const Yetani::PointPixel&) noexcept;
2080  std::string to_string(const Yetani::PointerAxis&) noexcept;
2081  std::string to_string(const Yetani::PointerAxisSource&) noexcept;
2082  std::string to_string(const Yetani::PointerAxisType&) noexcept;
2083  std::string to_string(const Yetani::PointerButtonState&) noexcept;
2084  std::string to_string(const Yetani::WindowMode&) noexcept;
2085 
2086  // }}}
2087 }
2088 
2089 // {{{ Implementation
2090 
2091 #ifdef ZAKERO_YETANI_IMPLEMENTATION
2092 
2093 // {{{ Macros
2094 
2095 // {{{ Macros : Doxygen
2096 
2097 #ifdef ZAKERO__DOXYGEN_DEFINE_DOCS
2098 
2099 // Only used for generating Doxygen documentation
2100 
2112 #define ZAKERO_YETANI_IMPLEMENTATION
2113 
2122 #define ZAKERO_YETANI_ENABLE_DEBUG
2123 
2132 #define ZAKERO_YETANI_ENABLE_SAFE_MODE
2133 
2134 #endif // ZAKERO__DOXYGEN_DEFINE_DOCS
2135 
2136 // }}}
2137 
2153 #ifdef ZAKERO_YETANI_ENABLE_DEBUG
2154 #define ZAKERO_YETANI__DEBUG_DISABLED false
2155 #else
2156 #define ZAKERO_YETANI__DEBUG_DISABLED true
2157 #endif
2158 
2159 
2172 #ifndef ZAKERO_YETANI_ENABLE_DEBUG_STREAM
2173 #define ZAKERO_YETANI_ENABLE_DEBUG_STREAM std::cerr
2174 #endif
2175 
2176 
2194 #define ZAKERO_YETANI__DEBUG \
2195  if(ZAKERO_YETANI__DEBUG_DISABLED) {} \
2196  else ZAKERO_YETANI_ENABLE_DEBUG_STREAM \
2197  << __FILE__"(" \
2198  << std::to_string(__LINE__) \
2199  << ") " \
2200  << __PRETTY_FUNCTION__ \
2201  << " "
2202 
2219 #define ZAKERO_YETANI__DEBUG_VAR(var_) \
2220  ZAKERO_YETANI__DEBUG \
2221  << #var_ << ": " << var_ \
2222  << "\n";
2223 
2239 #define ZAKERO_YETANI__DEBUG_BOOL(var_) \
2240  ZAKERO_YETANI__DEBUG \
2241  << #var_ << ": " << std::boolalpha << var_ \
2242  << "\n";
2243 
2254 #define ZAKERO_YETANI__ERROR(err_) std::error_code(err_, YetaniErrorCategory)
2255 
2256 
2273 #define ZAKERO_YETANI__SHM_FORMAT \
2274  X(WL_SHM_FORMAT_ARGB8888 , 4 , "32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian" ) \
2275  X(WL_SHM_FORMAT_XRGB8888 , 4 , "32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian" ) \
2276  X(WL_SHM_FORMAT_C8 , 1 , "8-bit color index format, [7:0] C" ) \
2277  X(WL_SHM_FORMAT_RGB332 , 1 , "8-bit RGB format, [7:0] R:G:B 3:3:2" ) \
2278  X(WL_SHM_FORMAT_BGR233 , 1 , "8-bit BGR format, [7:0] B:G:R 2:3:3" ) \
2279  X(WL_SHM_FORMAT_XRGB4444 , 2 , "16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian" ) \
2280  X(WL_SHM_FORMAT_XBGR4444 , 2 , "16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian" ) \
2281  X(WL_SHM_FORMAT_RGBX4444 , 2 , "16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian" ) \
2282  X(WL_SHM_FORMAT_BGRX4444 , 2 , "16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian" ) \
2283  X(WL_SHM_FORMAT_ARGB4444 , 2 , "16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian" ) \
2284  X(WL_SHM_FORMAT_ABGR4444 , 2 , "16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian" ) \
2285  X(WL_SHM_FORMAT_RGBA4444 , 2 , "16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian" ) \
2286  X(WL_SHM_FORMAT_BGRA4444 , 2 , "16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian" ) \
2287  X(WL_SHM_FORMAT_XRGB1555 , 2 , "16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian" ) \
2288  X(WL_SHM_FORMAT_XBGR1555 , 2 , "16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian" ) \
2289  X(WL_SHM_FORMAT_RGBX5551 , 2 , "16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian" ) \
2290  X(WL_SHM_FORMAT_BGRX5551 , 2 , "16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian" ) \
2291  X(WL_SHM_FORMAT_ARGB1555 , 2 , "16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian" ) \
2292  X(WL_SHM_FORMAT_ABGR1555 , 2 , "16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian" ) \
2293  X(WL_SHM_FORMAT_RGBA5551 , 2 , "16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian" ) \
2294  X(WL_SHM_FORMAT_BGRA5551 , 2 , "16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian" ) \
2295  X(WL_SHM_FORMAT_RGB565 , 2 , "16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian" ) \
2296  X(WL_SHM_FORMAT_BGR565 , 2 , "16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian" ) \
2297  X(WL_SHM_FORMAT_RGB888 , 3 , "24-bit RGB format, [23:0] R:G:B little endian" ) \
2298  X(WL_SHM_FORMAT_BGR888 , 3 , "24-bit BGR format, [23:0] B:G:R little endian" ) \
2299  X(WL_SHM_FORMAT_XBGR8888 , 4 , "32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian" ) \
2300  X(WL_SHM_FORMAT_RGBX8888 , 4 , "32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian" ) \
2301  X(WL_SHM_FORMAT_BGRX8888 , 4 , "32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian" ) \
2302  X(WL_SHM_FORMAT_ABGR8888 , 4 , "32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian" ) \
2303  X(WL_SHM_FORMAT_RGBA8888 , 4 , "32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian" ) \
2304  X(WL_SHM_FORMAT_BGRA8888 , 4 , "32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian" ) \
2305  X(WL_SHM_FORMAT_XRGB2101010 , 4 , "32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian" ) \
2306  X(WL_SHM_FORMAT_XBGR2101010 , 4 , "32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian" ) \
2307  X(WL_SHM_FORMAT_RGBX1010102 , 4 , "32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian" ) \
2308  X(WL_SHM_FORMAT_BGRX1010102 , 4 , "32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian" ) \
2309  X(WL_SHM_FORMAT_ARGB2101010 , 4 , "32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian" ) \
2310  X(WL_SHM_FORMAT_ABGR2101010 , 4 , "32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian" ) \
2311  X(WL_SHM_FORMAT_RGBA1010102 , 4 , "32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian" ) \
2312  X(WL_SHM_FORMAT_BGRA1010102 , 4 , "32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian" ) \
2313  X(WL_SHM_FORMAT_YUYV , 4 , "packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian" ) \
2314  X(WL_SHM_FORMAT_YVYU , 4 , "packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian" ) \
2315  X(WL_SHM_FORMAT_UYVY , 4 , "packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian" ) \
2316  X(WL_SHM_FORMAT_VYUY , 4 , "packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian" ) \
2317  X(WL_SHM_FORMAT_AYUV , 4 , "packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian" ) \
2318  X(WL_SHM_FORMAT_NV12 , 8 , "2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane" ) \
2319  X(WL_SHM_FORMAT_NV21 , 8 , "2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane" ) \
2320  X(WL_SHM_FORMAT_NV16 , 8 , "2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane" ) \
2321  X(WL_SHM_FORMAT_NV61 , 8 , "2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane" ) \
2322  X(WL_SHM_FORMAT_YUV410 , 8 , "3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes" ) \
2323  X(WL_SHM_FORMAT_YVU410 , 8 , "3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes" ) \
2324  X(WL_SHM_FORMAT_YUV411 , 8 , "3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes" ) \
2325  X(WL_SHM_FORMAT_YVU411 , 8 , "3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes" ) \
2326  X(WL_SHM_FORMAT_YUV420 , 8 , "3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes" ) \
2327  X(WL_SHM_FORMAT_YVU420 , 8 , "3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes" ) \
2328  X(WL_SHM_FORMAT_YUV422 , 8 , "3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes" ) \
2329  X(WL_SHM_FORMAT_YVU422 , 8 , "3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes" ) \
2330  X(WL_SHM_FORMAT_YUV444 , 8 , "3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes" ) \
2331  X(WL_SHM_FORMAT_YVU444 , 8 , "3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes" ) \
2332  X(WL_SHM_FORMAT_R8 , 1 , "[7:0] R" ) \
2333  X(WL_SHM_FORMAT_R16 , 2 , "[15:0] R little endian" ) \
2334  X(WL_SHM_FORMAT_RG88 , 2 , "[15:0] R:G 8:8 little endian" ) \
2335  X(WL_SHM_FORMAT_GR88 , 2 , "[15:0] G:R 8:8 little endian" ) \
2336  X(WL_SHM_FORMAT_RG1616 , 4 , "[31:0] R:G 16:16 little endian" ) \
2337  X(WL_SHM_FORMAT_GR1616 , 4 , "[31:0] G:R 16:16 little endian" ) \
2338  X(WL_SHM_FORMAT_XRGB16161616F , 8 , "[63:0] x:R:G:B 16:16:16:16 little endian" ) \
2339  X(WL_SHM_FORMAT_XBGR16161616F , 8 , "[63:0] x:B:G:R 16:16:16:16 little endian" ) \
2340  X(WL_SHM_FORMAT_ARGB16161616F , 8 , "[63:0] A:R:G:B 16:16:16:16 little endian" ) \
2341  X(WL_SHM_FORMAT_ABGR16161616F , 8 , "[63:0] A:B:G:R 16:16:16:16 little endian" ) \
2342  X(WL_SHM_FORMAT_XYUV8888 , 4 , "[31:0] X:Y:Cb:Cr 8:8:8:8 little endian" ) \
2343  X(WL_SHM_FORMAT_VUY888 , 3 , "[23:0] Cr:Cb:Y 8:8:8 little endian" ) \
2344  X(WL_SHM_FORMAT_VUY101010 , 4 , "Y followed by U then V, 10:10:10. Non-linear modifier only" ) \
2345  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" ) \
2346  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" ) \
2347  X(WL_SHM_FORMAT_Y216 , 8 , "[63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels" ) \
2348  X(WL_SHM_FORMAT_Y410 , 4 , "[31:0] A:Cr:Y:Cb 2:10:10:10 little endian" ) \
2349  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" ) \
2350  X(WL_SHM_FORMAT_Y416 , 8 , "[63:0] A:Cr:Y:Cb 16:16:16:16 little endian" ) \
2351  X(WL_SHM_FORMAT_XVYU2101010 , 4 , "[31:0] X:Cr:Y:Cb 2:10:10:10 little endian" ) \
2352  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" ) \
2353  X(WL_SHM_FORMAT_XVYU16161616 , 8 , "[63:0] X:Cr:Y:Cb 16:16:16:16 little endian" ) \
2354  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" ) \
2355  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" ) \
2356  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" ) \
2357  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" ) \
2358  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" ) \
2359  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" ) \
2360  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" ) \
2361  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" ) \
2362  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" ) \
2363  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" ) \
2364  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" ) \
2365  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" ) \
2366  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" ) \
2367  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" ) \
2368  X(WL_SHM_FORMAT_NV24 , 0 , "[UNKNOWN SIZE] non-subsampled Cr:Cb plane" ) \
2369  X(WL_SHM_FORMAT_NV42 , 0 , "[UNKNOWN SIZE] non-subsampled Cb:Cr plane" ) \
2370  X(WL_SHM_FORMAT_P210 , 0 , "[UNKNOWN SIZE] 2x1 subsampled Cr:Cb plane, 10 bits per channel" ) \
2371  X(WL_SHM_FORMAT_P010 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 10 bits per channel" ) \
2372  X(WL_SHM_FORMAT_P012 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 12 bits per channel" ) \
2373  X(WL_SHM_FORMAT_P016 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 16 bits per channel" ) \
2374 
2375 
2381 #define ZAKERO_YETANI__OUTPUT_SUBPIXEL \
2382  X(WL_OUTPUT_SUBPIXEL_UNKNOWN , "Unkown Subpixel Format" ) \
2383  X(WL_OUTPUT_SUBPIXEL_NONE , "No Subpixels" ) \
2384  X(WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB , "Horizontal RGB" ) \
2385  X(WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR , "Horizontal BGR" ) \
2386  X(WL_OUTPUT_SUBPIXEL_VERTICAL_RGB , "Vertical RGB" ) \
2387  X(WL_OUTPUT_SUBPIXEL_VERTICAL_BGR , "Vertical BGR" ) \
2388 
2389 
2395 #define ZAKERO_YETANI__OUTPUT_TRANSFORM \
2396  X(WL_OUTPUT_TRANSFORM_NORMAL , "No Transform" ) \
2397  X(WL_OUTPUT_TRANSFORM_90 , "90 degrees Counter-Clockwise" ) \
2398  X(WL_OUTPUT_TRANSFORM_180 , "180 degrees Counter-Clockwise" ) \
2399  X(WL_OUTPUT_TRANSFORM_270 , "270 degrees Counter-Clockwise" ) \
2400  X(WL_OUTPUT_TRANSFORM_FLIPPED , "180 degree flip around a vertical axis" ) \
2401  X(WL_OUTPUT_TRANSFORM_FLIPPED_90 , "Flig and rotate 90 degrees counter-clockwise" ) \
2402  X(WL_OUTPUT_TRANSFORM_FLIPPED_180 , "Flig and rotate 180 degrees counter-clockwise" ) \
2403 
2404 
2428 #define ZAKERO_YETANI__ARRAY_FOR_EACH(type_, pos_, array_) \
2429  for(type_ pos_ = (type_)(array_)->data \
2430  ; (const char*)pos_ < ((const char*)(array_)->data + (array_)->size) \
2431  ; (pos_)++ \
2432  )
2433 
2434 // }}}
2435 
2436 namespace zakero
2437 {
2438 // {{{ Anonymous Namespace
2439 
2440 namespace
2441 {
2442  // {{{ Cursor Names (Not used yet)
2443  /*
2444  * \brief Common cursor names
2445  *
2446  * These were found in:
2447  * - gdkcursor-wayland.c
2448  * - /usr/share/icons/whiteglass/cursors
2449  const std::array<const char*, 131> common_cursor_names =
2450  { "X_cursor"
2451  , "alias"
2452  , "all-scroll"
2453  , "arrow"
2454  , "base_arrow_down"
2455  , "base_arrow_up"
2456  , "bd_double_arrow"
2457  , "boat"
2458  , "bottom_left_corner"
2459  , "bottom_right_corner"
2460  , "bottom_side"
2461  , "bottom_tee"
2462  , "cell"
2463  , "center_ptr"
2464  , "circle"
2465  , "closedhand"
2466  , "col-resize"
2467  , "color-picker"
2468  , "context-menu"
2469  , "copy"
2470  , "cross"
2471  , "cross_reverse"
2472  , "crossed_circle"
2473  , "crosshair"
2474  , "default"
2475  , "dnd-copy"
2476  , "dnd-link"
2477  , "dnd-move"
2478  , "dnd-no-drop"
2479  , "dnd-none"
2480  , "dot"
2481  , "dot_box_mask"
2482  , "double_arrow"
2483  , "down-arrow"
2484  , "draft"
2485  , "draft_large"
2486  , "draft_small"
2487  , "draped_box"
2488  , "e-resize"
2489  , "ew-resize"
2490  , "exchange"
2491  , "fd_double_arrow"
2492  , "fleur"
2493  , "forbidden"
2494  , "grab"
2495  , "grabbing"
2496  , "gumby"
2497  , "h_double_arrow"
2498  , "half-busy"
2499  , "hand"
2500  , "hand1"
2501  , "hand2"
2502  , "help"
2503  , "ibeam"
2504  , "left-arrow"
2505  , "left_ptr"
2506  , "left_ptr_help"
2507  , "left_ptr_watch"
2508  , "left_side"
2509  , "left_tee"
2510  , "link"
2511  , "ll_angle"
2512  , "lr_angle"
2513  , "move"
2514  , "n-resize"
2515  , "ne-resize"
2516  , "nesw-resize"
2517  , "no-drop"
2518  , "not-allowed"
2519  , "ns-resize"
2520  , "nw-resize"
2521  , "nwse-resize"
2522  , "openhand"
2523  , "pencil"
2524  , "pirate"
2525  , "plus"
2526  , "pointer"
2527  , "pointing_hand"
2528  , "progress"
2529  , "question_arrow"
2530  , "right-arrow"
2531  , "right_ptr"
2532  , "right_side"
2533  , "right_tee"
2534  , "row-resize"
2535  , "s-resize"
2536  , "sailboat"
2537  , "sb_down_arrow"
2538  , "sb_h_double_arrow"
2539  , "sb_left_arrow"
2540  , "sb_right_arrow"
2541  , "sb_up_arrow"
2542  , "sb_v_double_arrow"
2543  , "se-resize"
2544  , "shuttle"
2545  , "size-bdiag"
2546  , "size-fdiag"
2547  , "size-hor"
2548  , "size-ver"
2549  , "size_all"
2550  , "size_bdiag"
2551  , "size_fdiag"
2552  , "size_hor"
2553  , "size_ver"
2554  , "sizing"
2555  , "split_h"
2556  , "split_v"
2557  , "sw-resize"
2558  , "target"
2559  , "tcross"
2560  , "text"
2561  , "top_left_arrow"
2562  , "top_left_corner"
2563  , "top_right_corner"
2564  , "top_side"
2565  , "top_tee"
2566  , "trek"
2567  , "ul_angle"
2568  , "up-arrow"
2569  , "ur_angle"
2570  , "v_double_arrow"
2571  , "vertical-text"
2572  , "w-resize"
2573  , "wait"
2574  , "watch"
2575  , "wayland-cursor"
2576  , "whats_this"
2577  , "x-cursor"
2578  , "xterm"
2579  , "zoom-in"
2580  , "zoom-out"
2581  };
2582  */
2583  // }}}
2584 
2594  class YetaniErrorCategory_
2595  : public std::error_category
2596  {
2597  public:
2598  constexpr YetaniErrorCategory_() noexcept
2599  {
2600  }
2601 
2602  const char* name() const noexcept override
2603  {
2604  return "zakero.Yetani";
2605  }
2606 
2607  std::string message(int condition
2608  ) const noexcept override
2609  {
2610  switch(condition)
2611  {
2612 #define X(name_, val_, mesg_) \
2613  case val_: return mesg_;
2614  ZAKERO_YETANI__ERROR_DATA
2615 #undef X
2616  }
2617 
2618  return "Unknown error condition";
2619  }
2620  } YetaniErrorCategory;
2621 
2622 
2627  Yetani::Lambda Lambda_DoNothing = []() noexcept {};
2628  Yetani::LambdaKey LambdaKey_DoNothing = [](const Yetani::Key&, const Yetani::KeyModifier&) noexcept {};
2629  Yetani::LambdaAxis LambdaAxis_DoNothing = [](const Yetani::PointerAxis&, const Yetani::KeyModifier&) noexcept {};
2630  Yetani::LambdaButtonMm LambdaButtonMm_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointMm&, const Yetani::KeyModifier&) noexcept {};
2631  Yetani::LambdaButtonPercent LambdaButtonPercent_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointPercent&, const Yetani::KeyModifier&) noexcept {};
2632  Yetani::LambdaButtonPixel LambdaButtonPixel_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointPixel&, const Yetani::KeyModifier&) noexcept {};
2633  Yetani::LambdaPointMm LambdaPointMm_DoNothing = [](const Yetani::PointMm&, const Yetani::KeyModifier&) noexcept {};
2634  Yetani::LambdaPointPercent LambdaPointPercent_DoNothing = [](const Yetani::PointPercent&, const Yetani::KeyModifier&) noexcept {};
2635  Yetani::LambdaPointPixel LambdaPointPixel_DoNothing = [](const Yetani::PointPixel&, const Yetani::KeyModifier&) noexcept {};
2636  Yetani::LambdaBool LambdaBool_DoNothing = [](const bool) noexcept {};
2637  Yetani::LambdaOutputId LambdaOutputId_DoNothing = [](const Yetani::OutputId) noexcept {};
2638  Yetani::LambdaWindowDecorations LambdaWindowDecorations_DoNothing = [](const Yetani::WindowDecorations) noexcept {};
2639  Yetani::LambdaWindowMode LambdaWindowMode_DoNothing = [](const Yetani::WindowMode) noexcept {};
2640  Yetani::LambdaSizeMm LambdaSizeMm_DoNothing = [](const Yetani::SizeMm&) noexcept {};
2641  Yetani::LambdaSizePercent LambdaSizePercent_DoNothing = [](const Yetani::SizePercent&) noexcept {};
2642  Yetani::LambdaSizePixel LambdaSizePixel_DoNothing = [](const Yetani::SizePixel&) noexcept {};
2660  inline size_t sizeInBytes(const Yetani::SizePixel& size
2661  , const wl_shm_format format
2662  ) noexcept
2663  {
2664  return size.width
2665  * size.height
2667  ;
2668  }
2669 
2670 
2684  template<class Type
2685  >
2686  std::error_code validateMinMax(const Type& min
2687  , const Type& max
2688  ) noexcept
2689  {
2690  if((min.width < 0)
2691  || (min.height < 0)
2692  || (max.width < 0)
2693  || (max.height < 0)
2694  )
2695  {
2696  return ZAKERO_YETANI__ERROR(Yetani::Error_Window_Size_Too_Small);
2697  }
2698 
2699  if((min.width > 0)
2700  && (max.width > 0)
2701  && (min.width > max.width)
2702  )
2703  {
2704  return ZAKERO_YETANI__ERROR(Yetani::Error_Minimum_Size_Greater_Than_Maximum_Size);
2705  }
2706 
2707  if((min.height > 0)
2708  && (max.height > 0)
2709  && (min.height > max.height)
2710  )
2711  {
2712  return ZAKERO_YETANI__ERROR(Yetani::Error_Minimum_Size_Greater_Than_Maximum_Size);
2713  }
2714 
2715  return ZAKERO_YETANI__ERROR(Yetani::Error_None);
2716  }
2717 }
2718 
2719 // }}}
2720 // {{{ Documentation
2721 
2878 /* Disabled because Doxygen does not support "enum classes"
2879  *
2880  * \var Yetani::Released
2881  * \brief The key was released
2882  *
2883  * \var Yetani::Pressed
2884  * \brief The key was pressed
2885  *
2886  * \var Yetani::Repeat
2887  * \brief The key is being held down
2888  */
2889 
3004 /* Disabled because Doxygen does not support "enum classes"
3005  *
3006  * \var Yetani::Unknown
3007  * \brief Unknown
3008  *
3009  * \var Yetani::Continuous
3010  * \brief Continuous
3011  *
3012  * \var Yetani::Finger
3013  * \brief Finger
3014  *
3015  * \var Yetani::Wheel
3016  * \brief Wheel
3017  *
3018  * \var Yetani::Wheel_Tilt
3019  * \brief Wheel Tilt
3020  */
3021 
3027 /* Disabled because Doxygen does not support "enum classes"
3028  *
3029  * \var Yetani::Unknown
3030  * \brief Unknown
3031  *
3032  * \var Yetani::Horizontal
3033  * \brief Horizontal
3034  *
3035  * \var Yetani::Vertical
3036  * \brief Vertical
3037  */
3038 
3065 /* Disabled because Doxygen does not support "enum classes"
3066  *
3067  * \var Yetani::Released
3068  * \brief Released
3069  *
3070  * \var Yetani::Pressed
3071  * \brief Pressed
3072  */
3073 
3125 // }}}
3126 // {{{ Static Member Initialization
3127 // {{{ Listener Handler : Wayland
3128 
3129 struct wl_buffer_listener Yetani::buffer_listener =
3130 { .release = &Yetani::handlerBufferRelease
3131 };
3132 
3133 struct wl_callback_listener Yetani::frame_callback_listener =
3134 { .done = &Yetani::handlerSwapBuffers
3135 };
3136 
3137 struct wl_keyboard_listener Yetani::keyboard_listener =
3138 { .keymap = &Yetani::handlerKeyboardKeymap
3139 , .enter = &Yetani::handlerKeyboardEnter
3140 , .leave = &Yetani::handlerKeyboardLeave
3141 , .key = &Yetani::handlerKeyboardKey
3142 , .modifiers = &Yetani::handlerKeyboardModifiers
3143 , .repeat_info = &Yetani::handlerKeyboardRepeatInfo
3144 };
3145 
3146 struct wl_output_listener Yetani::output_listener =
3147 { .geometry = &Yetani::handlerOutputGeometry
3148 , .mode = &Yetani::handlerOutputMode
3149 , .done = &Yetani::handlerOutputDone
3150 , .scale = &Yetani::handlerOutputScale
3151 };
3152 
3153 struct wl_pointer_listener Yetani::pointer_listener =
3154 { .enter = &Yetani::handlerPointerEnter
3155 , .leave = &Yetani::handlerPointerLeave
3156 , .motion = &Yetani::handlerPointerMotion
3157 , .button = &Yetani::handlerPointerButton
3158 , .axis = &Yetani::handlerPointerAxis
3159 , .frame = &Yetani::handlerPointerFrame
3160 , .axis_source = &Yetani::handlerPointerAxisSource
3161 , .axis_stop = &Yetani::handlerPointerAxisStop
3162 , .axis_discrete = &Yetani::handlerPointerAxisDiscrete
3163 };
3164 
3165 struct wl_registry_listener Yetani::registry_listener =
3166 { .global = &Yetani::handlerRegistryGlobal
3167 , .global_remove = &Yetani::handlerRegistryRemove
3168 };
3169 
3170 struct wl_seat_listener Yetani::seat_listener =
3171 { .capabilities = &Yetani::handlerSeatCapabilities
3172 , .name = &Yetani::handlerSeatName
3173 };
3174 
3175 struct wl_shm_listener Yetani::shm_listener =
3176 { .format = &Yetani::handlerShmFormat
3177 };
3178 
3179 struct wl_surface_listener Yetani::surface_listener =
3180 { .enter = &Yetani::handlerSurfaceEnter
3181 , .leave = &Yetani::handlerSurfaceLeave
3182 };
3183 
3184 // }}}
3185 // {{{ Listener Handler : Wayland Unstable
3186 // }}}
3187 // {{{ Listener Handler : XDG
3188 
3189 struct xdg_wm_base_listener Yetani::xdg_wm_base_listener =
3190 { .ping = &Yetani::handlerXdgWmBasePing
3191 };
3192 
3193 struct xdg_surface_listener Yetani::xdg_surface_listener =
3194 { .configure = &Yetani::handlerXdgSurfaceConfigure
3195 };
3196 
3197 struct xdg_toplevel_listener Yetani::xdg_toplevel_listener =
3198 { .configure = &Yetani::handlerXdgToplevelConfigure
3199 , .close = &Yetani::handlerXdgToplevelClose
3200 };
3201 
3202 // }}}
3203 // {{{ Listener Handler : XDG Unstable
3204 
3205 struct zxdg_toplevel_decoration_v1_listener Yetani::xdg_toplevel_decoration_listener =
3206 { .configure = &Yetani::handlerXdgToplevelDecorationConfigure
3207 };
3208 
3209 // }}}
3210 // }}}
3211 // {{{ Constructor / Destructor
3212 
3218 Yetani::Yetani() noexcept
3219  : cursor_map()
3220  , cursor_surface_map()
3221  , cursor_memory_pool(
3222  std::string("Zakero.Yetani.")
3223  + std::to_string(ZAKERO_STEADY_TIME_NOW(nanoseconds))
3224  )
3225  , cursor_mutex()
3226  , cursor_shm_pool(nullptr)
3227  , cursor_pointer(nullptr)
3228  , event_loop()
3229  , event_loop_is_running(false)
3230  , compositor(nullptr)
3231  , display(nullptr)
3232  , registry(nullptr)
3233  , shm(nullptr)
3234  , shm_format_vector()
3235  , seat_map()
3236  , id_to_seat()
3237  , seat(nullptr)
3238  , keyboard()
3239  , pointer()
3240  , output_data()
3241  , on_output_add(LambdaOutputId_DoNothing)
3242  , on_output_change(LambdaOutputId_DoNothing)
3243  , on_output_remove(LambdaOutputId_DoNothing)
3244  , output_changes_map()
3245  , output_state_map()
3246  , output_notify_surface_vector()
3247  , buffer()
3248  , surface_event_map()
3249  , surface_extent_map()
3250  , surface_extent_mutex()
3251  , surface_frame_map()
3252  , surface_size_map()
3253  , surface_resize_mutex_map()
3254  , window_vector()
3255  , window_vector_mutex()
3256  , xdg_state_change_map()
3257  , xdg_state_change_mutex()
3258  , xdg_wm_base(nullptr)
3259  , xdg_surface_map()
3260  , xdg_toplevel_map()
3261  , xdg_decoration_map()
3262  , decoration_manager(nullptr)
3263 {
3264 }
3265 
3266 
3277 {
3278  if(event_loop_is_running || event_loop.joinable())
3279  {
3280  event_loop.request_stop();
3281  event_loop.join();
3282  }
3283 
3284  disconnect();
3285 }
3286 
3287 // }}}
3288 // {{{ Connection
3289 
3313 {
3314  std::error_code error;
3315 
3316  return Yetani::connect("", error);
3317 }
3318 
3319 
3344 Yetani* Yetani::connect(const std::string& display
3345  ) noexcept
3346 {
3347  std::error_code error;
3348 
3349  return Yetani::connect(display, error);
3350 }
3351 
3352 
3380 Yetani* Yetani::connect(std::error_code& error
3381  ) noexcept
3382 {
3383  return Yetani::connect("", error);
3384 }
3385 
3415 Yetani* Yetani::connect(const std::string& display
3416  , std::error_code& error
3417  ) noexcept
3418 {
3419  Yetani* yetani = new Yetani();
3420 
3421  const char* display_name = nullptr;
3422 
3423  if(display.empty() == false)
3424  {
3425  display_name = display.c_str();
3426  }
3427 
3428  // --- Get the Display --- //
3429  yetani->display = wl_display_connect(display_name);
3430  if(yetani->display == nullptr)
3431  {
3432  delete yetani;
3433 
3434  const char* session = getenv("XDG_SESSION_TYPE");
3435 
3436  if(session != nullptr
3437  && strcasecmp(session, "wayland") != 0
3438  )
3439  {
3440  error = ZAKERO_YETANI__ERROR(Error_Wayland_Not_Available);
3441  }
3442  else if(display.empty())
3443  {
3444  error = ZAKERO_YETANI__ERROR(Error_Connection_Failed);
3445  }
3446  else
3447  {
3448  error = ZAKERO_YETANI__ERROR(Error_Invalid_Display_Name);
3449  }
3450 
3451  return nullptr;
3452  }
3453 
3454  // --- Get the Registry --- //
3455  yetani->registry = wl_display_get_registry(yetani->display);
3456  if(yetani->registry == nullptr)
3457  {
3458  delete yetani;
3459 
3460  error = ZAKERO_YETANI__ERROR(Error_Registry_Not_Available);
3461 
3462  return nullptr;
3463  }
3464 
3465  wl_registry_add_listener(yetani->registry, &registry_listener, yetani);
3466 
3467  // --- Wait for all Global Objects to be registered --- //
3468  wl_display_dispatch(yetani->display);
3469  wl_display_roundtrip(yetani->display);
3470 
3471  // --- Validate required Global Objects --- //
3472  if(yetani->compositor == nullptr)
3473  {
3474  delete yetani;
3475 
3476  error = ZAKERO_YETANI__ERROR(Error_Compositor_Was_Not_Found);
3477 
3478  return nullptr;
3479  }
3480 
3481  if(yetani->shm == nullptr)
3482  {
3483  delete yetani;
3484 
3485  error = ZAKERO_YETANI__ERROR(Error_Shm_Was_Not_Found);
3486 
3487  return nullptr;
3488  }
3489 
3490  if(yetani->xdg_wm_base == nullptr)
3491  {
3492  delete yetani;
3493 
3494  error = ZAKERO_YETANI__ERROR(Error_Xdg_WM_Base_Was_Not_Found);
3495 
3496  return nullptr;
3497  }
3498 
3499  yetani->cursorSetup();
3500 
3501  yetani->eventLoopStart();
3502 
3503  error = ZAKERO_YETANI__ERROR(Error_None);
3504 
3505  return yetani;
3506 }
3507 
3508 
3518 void Yetani::disconnect() noexcept
3519 {
3520  cursorTeardown();
3521 
3522  if(decoration_manager != nullptr)
3523  {
3524  zxdg_decoration_manager_v1_destroy(decoration_manager);
3525  decoration_manager = nullptr;
3526  }
3527 
3528  if(xdg_wm_base != nullptr)
3529  {
3530  xdg_wm_base_destroy(xdg_wm_base);
3531  xdg_wm_base = nullptr;
3532  }
3533 
3534  if(shm != nullptr)
3535  {
3536  wl_shm_destroy(shm);
3537  shm = nullptr;
3538  }
3539 
3540  // Seat
3541  id_to_seat.clear();
3542 
3543  while(seat_map.empty() == false)
3544  {
3545  auto iter = std::begin(seat_map);
3546 
3547  struct wl_seat* wl_seat = iter->first;
3548 
3549  seatDestroy(wl_seat);
3550  }
3551 
3552  // Wayland Output Devices
3553  {
3554  std::lock_guard<std::mutex> lock(output_data.mutex);
3555 
3556  for(auto& iter : output_data.output_map)
3557  {
3558  struct wl_output* wayland_output = iter.first;
3559 
3560  wl_output_destroy(wayland_output);
3561  }
3562 
3563  output_changes_map.clear();
3564  output_state_map.clear();
3565  output_data.output_map.clear();
3566  output_data.wloutput_to_outputid.clear();
3567  output_data.outputid_to_wloutput.clear();
3568  }
3569 
3570  if(registry != nullptr)
3571  {
3572  wl_registry_destroy(registry);
3573  registry = nullptr;
3574  }
3575 
3576  if(compositor != nullptr)
3577  {
3578  wl_compositor_destroy(compositor);
3579  compositor = nullptr;
3580  }
3581 
3582  if(display != nullptr)
3583  {
3584  wl_display_disconnect(display);
3585  display = nullptr;
3586  }
3587 
3588  return;
3589 }
3590 
3591 // }}}
3592 // {{{ Cursor
3593 
3726 void Yetani::cursorAnimate() noexcept
3727 {
3728  int64_t time_now = ZAKERO_STEADY_TIME_NOW(milliseconds);
3729 
3730  std::lock_guard<std::mutex> lock(cursor_mutex);
3731 
3732  for(auto& iter : cursor_map)
3733  {
3734  Yetani::Cursor& cursor = iter.second;
3735 
3736  if(cursor.next_frame_time <= time_now)
3737  {
3738  const int64_t time_over = time_now - cursor.next_frame_time;
3739  cursor.next_frame_time = time_now + cursor.time_per_frame - time_over;
3740 
3741  cursor.buffer_index = (cursor.buffer_index + 1) % cursor.buffer_vector.size();
3742 
3743  wl_surface_attach(cursor.wl_surface, cursor.buffer_vector[cursor.buffer_index], 0, 0);
3744  wl_surface_damage(cursor.wl_surface
3745  , 0, 0
3746  , cursor.width, cursor.height
3747  );
3748 
3749  wl_surface_commit(cursor.wl_surface);
3750  }
3751  }
3752 }
3753 
3754 
3795 std::error_code Yetani::cursorCreate(const std::string& name
3796  , const Yetani::CursorConfig& config
3797  ) noexcept
3798 {
3799  if(name.empty())
3800  {
3801  return ZAKERO_YETANI__ERROR(Error_Cursor_Name_Is_Invalid);
3802  }
3803 
3804  if(cursor_map.contains(name) == true)
3805  {
3806  return ZAKERO_YETANI__ERROR(Error_Cursor_Already_Exists);
3807  }
3808 
3809  if(config.size.width <= 0 || config.size.height <= 0)
3810  {
3811  return ZAKERO_YETANI__ERROR(Error_Cursor_Size_Too_Small);
3812  }
3813 
3814  if(config.image_data.empty())
3815  {
3816  return ZAKERO_YETANI__ERROR(Error_Cursor_Image_Data_Is_Empty);
3817  }
3818  else if(config.image_data.size() > 1)
3819  {
3820  if(config.time_per_frame.count() <= 0)
3821  {
3822  return ZAKERO_YETANI__ERROR(Error_Cursor_Frame_Time_Too_Small);
3823  }
3824 
3825  if(config.time_per_frame.count() > Size_Max)
3826  {
3827  return ZAKERO_YETANI__ERROR(Error_Cursor_Frame_Time_Too_Large);
3828  }
3829  }
3830 
3831  std::error_code error = cursorCreateCursor(name, config);
3832 
3833  return error;
3834 }
3835 
3836 
3847 std::error_code Yetani::cursorCreateCursor(const std::string& cursor_name
3848  , const Yetani::CursorConfig& cursor_config
3849  ) noexcept
3850 {
3851  const uint8_t bytes_per_pixel = shmFormatBytesPerPixel(cursor_config.format);
3852  const size_t frame_count = cursor_config.image_data.size();
3853 
3854  Yetani::Cursor cursor =
3855  { .wl_surface = wl_compositor_create_surface(compositor)
3856  , .buffer_vector = { frame_count, nullptr }
3857  , .format = cursor_config.format
3858  , .next_frame_time = ZAKERO_STEADY_TIME_NOW(milliseconds)
3859  , .buffer_index = 0
3860  , .time_per_frame = uint32_t(cursor_config.time_per_frame.count())
3861  , .width = cursor_config.size.width
3862  , .height = cursor_config.size.height
3863  , .hotspot_x = cursor_config.hotspot_x
3864  , .hotspot_y = cursor_config.hotspot_y
3865  };
3866 
3867  if(cursor.time_per_frame == 0)
3868  {
3869  cursor.time_per_frame = Size_Max;
3870  }
3871 
3872  const int stride = cursor.width * bytes_per_pixel;
3873  const size_t image_size = stride * cursor.height;
3874 
3875  for(size_t i = 0; i < frame_count; i++)
3876  {
3877  std::error_code error;
3878 
3879  off_t offset = cursor_memory_pool.alloc(image_size, error);
3880  if(error)
3881  {
3882  while(i > 0)
3883  {
3884  i--;
3885 
3886  struct wl_buffer* buffer = cursor.buffer_vector[i];
3887  cursor.buffer_vector[i] = nullptr;
3888 
3889  off_t offset = (off_t)wl_buffer_get_user_data(buffer);
3890  wl_buffer_destroy(buffer);
3891 
3892  cursor_memory_pool.free(offset);
3893  }
3894 
3895  return error;
3896  }
3897 
3898  uint32_t* p = (uint32_t*)cursor_memory_pool.addressOf(offset);
3899  memcpy(p, (uint8_t*)cursor_config.image_data[i], image_size);
3900 
3901  cursor.buffer_vector[i] = wl_shm_pool_create_buffer(cursor_shm_pool
3902  , offset
3903  , cursor.width
3904  , cursor.height
3905  , stride
3906  , cursor.format
3907  );
3908 
3909  wl_buffer_set_user_data(cursor.buffer_vector[i], (void*)offset);
3910  }
3911 
3912  wl_surface_attach(cursor.wl_surface, cursor.buffer_vector[0], 0, 0);
3913  wl_surface_commit(cursor.wl_surface);
3914 
3915  std::lock_guard<std::mutex> lock(cursor_mutex);
3916 
3917  cursor_map[cursor_name] = cursor;
3918 
3919  return ZAKERO_YETANI__ERROR(Error_None);
3920 }
3921 
3922 
3933 std::error_code Yetani::cursorDestroy(const std::string& name
3934  ) noexcept
3935 {
3936  Yetani::Cursor cursor;
3937 
3938  {
3939  std::lock_guard<std::mutex> lock(cursor_mutex);
3940 
3941  if(cursor_map.contains(name) == false)
3942  {
3943  return ZAKERO_YETANI__ERROR(Error_Cursor_Does_Not_Exist);
3944  }
3945 
3946  cursor = cursor_map[name];
3947 
3948  cursor_map.erase(name);
3949  }
3950 
3951  auto iter = std::begin(cursor_surface_map);
3952  auto iter_end = std::end(cursor_surface_map);
3953  while(iter != iter_end)
3954  {
3955  if(cursor.wl_surface == iter->second.wl_surface)
3956  {
3957  iter = cursor_surface_map.erase(iter);
3958  }
3959  else
3960  {
3961  iter++;
3962  }
3963  }
3964 
3965  if(cursor.wl_surface)
3966  {
3967  wl_surface_destroy(cursor.wl_surface);
3968  cursor.wl_surface = nullptr;
3969  }
3970 
3971  for(wl_buffer* buffer : cursor.buffer_vector)
3972  {
3973  off_t offset = (off_t)wl_buffer_get_user_data(buffer);
3974  wl_buffer_destroy(buffer);
3975 
3976  cursor_memory_pool.free(offset);
3977  }
3978 
3979  return ZAKERO_YETANI__ERROR(Error_None);
3980 }
3981 
3982 
3991 void Yetani::cursorEnter(wl_pointer* wl_pointer
3992  , uint32_t serial
3993  , struct wl_surface* wl_surface
3994  ) noexcept
3995 {
3996  std::lock_guard<std::mutex> lock(cursor_mutex);
3997 
3998  cursor_pointer = wl_pointer;
3999 
4000  if(cursor_surface_map.contains(wl_surface) == false)
4001  {
4002  return;
4003  }
4004 
4005  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4006 
4007  cursor_surface.wl_pointer = wl_pointer;
4008  cursor_surface.serial = serial;
4009 
4010  if(cursor_surface.is_visible)
4011  {
4012  wl_pointer_set_cursor(cursor_surface.wl_pointer
4013  , cursor_surface.serial
4014  , cursor_surface.wl_surface
4015  , cursor_surface.hotspot_x
4016  , cursor_surface.hotspot_y
4017  );
4018  }
4019  else
4020  {
4021  wl_pointer_set_cursor(cursor_surface.wl_pointer
4022  , cursor_surface.serial
4023  , nullptr
4024  , 0
4025  , 0
4026  );
4027  }
4028 }
4029 
4030 
4040 void Yetani::cursorLeave(struct wl_surface* wl_surface
4041  ) noexcept
4042 {
4043  std::lock_guard<std::mutex> lock(cursor_mutex);
4044 
4045  cursor_pointer = nullptr;
4046 
4047  if(cursor_surface_map.contains(wl_surface) == false)
4048  {
4049  return;
4050  }
4051 
4052  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4053 
4054  cursor_surface.wl_pointer = nullptr;
4055  cursor_surface.serial = 0;
4056 }
4057 
4058 
4066 void Yetani::cursorHide(struct wl_surface* wl_surface
4067  ) noexcept
4068 {
4069  std::lock_guard<std::mutex> lock(cursor_mutex);
4070 
4071  if(cursor_surface_map.contains(wl_surface) == false)
4072  {
4073  return;
4074  }
4075 
4076  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4077 
4078  cursor_surface.is_visible = false;
4079 
4080  if(cursor_surface.wl_pointer != nullptr)
4081  {
4082  wl_pointer_set_cursor(cursor_surface.wl_pointer
4083  , cursor_surface.serial
4084  , nullptr
4085  , 0
4086  , 0
4087  );
4088  }
4089 }
4090 
4091 
4099 void Yetani::cursorShow(struct wl_surface* wl_surface
4100  ) noexcept
4101 {
4102  std::lock_guard<std::mutex> lock(cursor_mutex);
4103 
4104  if(cursor_surface_map.contains(wl_surface) == false)
4105  {
4106  return;
4107  }
4108 
4109  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4110 
4111  cursor_surface.is_visible = true;
4112 
4113  if(cursor_surface.wl_pointer != nullptr)
4114  {
4115  wl_pointer_set_cursor(cursor_surface.wl_pointer
4116  , cursor_surface.serial
4117  , cursor_surface.wl_surface
4118  , cursor_surface.hotspot_x
4119  , cursor_surface.hotspot_y
4120  );
4121  }
4122 }
4123 
4124 
4135 bool Yetani::cursorIsHidden(struct wl_surface* wl_surface
4136  ) const noexcept
4137 {
4138  std::lock_guard<std::mutex> lock(cursor_mutex);
4139 
4140  if(cursor_surface_map.contains(wl_surface) == false)
4141  {
4142  return true;
4143  }
4144 
4145  const Yetani::CursorSurface& cursor_surface = cursor_surface_map.at(wl_surface);
4146 
4147  return !(cursor_surface.is_visible);
4148 }
4149 
4150 
4158 void Yetani::cursorSetup() noexcept
4159 {
4160  cursor_map.clear();
4161 
4162  uint64_t bytes = zakero::convert((uint64_t)4, zakero::Storage::Kilobyte, zakero::Storage::Byte);
4163  cursor_memory_pool.init(bytes, true, zakero::MemoryPool::Alignment::Bits_32);
4164 
4165  cursor_memory_pool.sizeOnChange([&](size_t new_size)
4166  {
4167  wl_shm_pool_resize(cursor_shm_pool, new_size);
4168  });
4169 
4170  cursor_shm_pool = wl_shm_create_pool(shm, cursor_memory_pool.fd(), cursor_memory_pool.size());
4171 }
4172 
4173 
4181 void Yetani::cursorTeardown() noexcept
4182 {
4183  while(cursor_map.empty() == false)
4184  {
4185  const auto& iter = cursor_map.begin();
4186 
4187  const std::string& name = iter->first;
4188 
4189  cursorDestroy(name);
4190  }
4191 
4192  if(cursor_shm_pool != nullptr)
4193  {
4194  wl_shm_pool_destroy(cursor_shm_pool);
4195  }
4196 }
4197 
4198 
4210 std::error_code Yetani::cursorAttach(const std::string& cursor_name
4211  , struct wl_surface* wl_surface
4212  ) noexcept
4213 {
4214  std::lock_guard<std::mutex> lock(cursor_mutex);
4215 
4216  if(cursor_map.contains(cursor_name) == false)
4217  {
4218  return ZAKERO_YETANI__ERROR(Error_Cursor_Does_Not_Exist);
4219  }
4220 
4221  if(cursor_surface_map.contains(wl_surface) == false)
4222  {
4223  cursor_surface_map[wl_surface] =
4224  { .wl_pointer = cursor_pointer
4225  , .wl_surface = nullptr
4226  , .serial = 0
4227  , .hotspot_x = 0
4228  , .hotspot_y = 0
4229  , .is_visible = true
4230  };
4231  }
4232 
4233  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4234  Yetani::Cursor& cursor = cursor_map[cursor_name];
4235 
4236  cursor_surface.wl_surface = cursor.wl_surface;
4237  cursor_surface.hotspot_x = cursor.hotspot_x;
4238  cursor_surface.hotspot_y = cursor.hotspot_y;
4239 
4240  if(cursor_surface.wl_pointer != nullptr)
4241  {
4242  if(cursor_surface.is_visible)
4243  {
4244  wl_pointer_set_cursor(cursor_surface.wl_pointer
4245  , cursor_surface.serial
4246  , cursor_surface.wl_surface
4247  , cursor_surface.hotspot_x
4248  , cursor_surface.hotspot_y
4249  );
4250  }
4251  else
4252  {
4253  wl_pointer_set_cursor(cursor_surface.wl_pointer
4254  , cursor_surface.serial
4255  , nullptr
4256  , 0
4257  , 0
4258  );
4259  }
4260  }
4261 
4262  return ZAKERO_YETANI__ERROR(Error_None);
4263 }
4264 
4265 
4277 std::error_code Yetani::cursorDetach(struct wl_surface* wl_surface
4278  ) noexcept
4279 {
4280  std::lock_guard<std::mutex> lock(cursor_mutex);
4281 
4282  if(cursor_surface_map.contains(wl_surface) == false)
4283  {
4284  return ZAKERO_YETANI__ERROR(Error_Cursor_Not_Attached);
4285  }
4286 
4287  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4288 
4289  if(cursor_surface.wl_pointer != nullptr)
4290  {
4291  wl_pointer_set_cursor(cursor_surface.wl_pointer
4292  , cursor_surface.serial
4293  , nullptr
4294  , 0
4295  , 0
4296  );
4297  }
4298 
4299  cursor_surface_map.erase(wl_surface);
4300 
4301  return ZAKERO_YETANI__ERROR(Error_None);
4302 }
4303 
4304 // }}}
4305 // {{{ Event Loop
4306 
4307 //#define ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4308 
4317 void Yetani::eventLoopStart() noexcept
4318 {
4319  event_loop = std::jthread(&Yetani::eventLoop, this);
4320 
4321  while(event_loop_is_running.load() == false)
4322  {
4323  // Wait for the thread to start
4324  std::this_thread::sleep_for(std::chrono::nanoseconds(42));
4325  }
4326 
4327  #ifdef ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4328  int policy = SCHED_FIFO;
4329  int priority_min = sched_get_priority_min(policy);
4330  int priority_max = sched_get_priority_max(policy);
4331 
4332  sched_param sched =
4333  { .sched_priority = (priority_min + priority_max) / 2
4334  };
4335 
4336  pthread_setschedparam(event_loop.native_handle(), policy, &sched);
4337  #endif
4338 }
4339 
4340 
4368 void Yetani::eventLoop(std::stop_token thread_token
4369  , Yetani* yetani
4370  ) noexcept
4371 {
4372  struct pollfd fd_status =
4373  { .fd = wl_display_get_fd(yetani->display)
4374  , .events = POLLIN | POLLOUT
4375  , .revents = 0
4376  };
4377 
4378  yetani->event_loop_is_running.store(true);
4379 
4380  // Handle events and render window contents
4381  while(thread_token.stop_requested() == false)
4382  {
4383  poll(&fd_status, 1, 1);
4384 
4385  if(fd_status.revents & POLLIN)
4386  {
4387  wl_display_dispatch(yetani->display);
4388  }
4389 
4390  yetani->cursorAnimate();
4391 
4392  keyboardRepeat(yetani->keyboard);
4393 
4394  if(fd_status.revents & POLLOUT)
4395  {
4396  wl_display_flush(yetani->display);
4397  }
4398 
4399  #ifdef ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4400  std::this_thread::yield();
4401  #endif
4402  }
4403 
4404  yetani->event_loop_is_running.store(false);
4405 }
4406 
4407 // }}}
4408 // {{{ Shared Memory
4409 
4420 const Yetani::VectorShmFormat& Yetani::shmFormatAvailable() const noexcept
4421 {
4422  return shm_format_vector;
4423 }
4424 
4425 
4437 uint8_t Yetani::shmFormatBytesPerPixel(const wl_shm_format shm_format
4438  ) noexcept
4439 {
4440  switch(shm_format)
4441  {
4442 #define X(value_, bytes_, desc_) \
4443  case value_: return bytes_;
4444  ZAKERO_YETANI__SHM_FORMAT
4445 #undef X
4446  default: return 0;
4447  }
4448 }
4449 
4450 
4462 std::string Yetani::shmFormatDescription(const wl_shm_format shm_format
4463  ) noexcept
4464 {
4465  switch(shm_format)
4466  {
4467 #define X(value_, bytes_, desc_) \
4468  case value_: return desc_;
4469  ZAKERO_YETANI__SHM_FORMAT
4470 #undef X
4471  default: return "";
4472  }
4473 }
4474 
4475 
4485 std::string Yetani::shmFormatName(const wl_shm_format shm_format
4486  ) noexcept
4487 {
4488  switch(shm_format)
4489  {
4490 #define X(value_, bytes_, desc_) \
4491  case value_: return #value_;
4492  ZAKERO_YETANI__SHM_FORMAT
4493 #undef X
4494  default: return "";
4495  }
4496 }
4497 
4498 // }}}
4499 // {{{ Utility
4500 
4501 
4502 // }}}
4503 // {{{ Wayland : Buffer
4504 
4545 struct wl_buffer* Yetani::bufferCreate(Yetani::SurfaceSize& surface_size
4546  , Yetani::Window::Memory* window_memory
4547  , Yetani::Buffer* buffer
4548  ) noexcept
4549 {
4550  off_t offset = window_memory->memory_pool.alloc(surface_size.in_bytes);
4551 
4552  struct wl_buffer* wl_buffer = wl_shm_pool_create_buffer(window_memory->wl_shm_pool
4553  , offset
4554  , surface_size.width
4555  , surface_size.height
4556  , surface_size.stride
4557  , surface_size.pixel_format
4558  );
4559 
4560  wl_buffer_set_user_data(wl_buffer, buffer);
4561 
4562  buffer->mutex.lock();
4563  {
4564  buffer->map[wl_buffer] =
4565  { .memory_pool = &window_memory->memory_pool
4566  , .offset = offset
4567  };
4568  }
4569  buffer->mutex.unlock();
4570 
4571  return wl_buffer;
4572 }
4573 
4574 
4584 void Yetani::bufferDestroy(struct wl_buffer*& wl_buffer
4585  ) noexcept
4586 {
4587  Yetani::Buffer* buffer = (Yetani::Buffer*)wl_buffer_get_user_data(wl_buffer);
4588 
4589  wl_buffer_destroy(wl_buffer);
4590 
4591  buffer->mutex.lock();
4592  {
4593  BufferData& buffer_data = buffer->map[wl_buffer];
4594 
4595  buffer_data.memory_pool->free(buffer_data.offset);
4596 
4597  buffer->map.erase(wl_buffer);
4598  }
4599  buffer->mutex.unlock();
4600 
4601  wl_buffer = nullptr;
4602 }
4603 
4604 // }}}
4605 // {{{ Wayland : Output
4606 
4702 Yetani::Output Yetani::output(const Yetani::OutputId output_id
4703  ) const noexcept
4704 {
4705  std::lock_guard<std::mutex> lock(output_data.mutex);
4706 
4707  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4708  {
4709  ZAKERO_YETANI__DEBUG
4710  << "Invalid output_id: "
4711  << std::to_string(output_id)
4712  ;
4713 
4714  return {};
4715  }
4716 
4717  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4718 
4719  return output_data.output_map.at(wl_output);
4720 }
4721 
4722 
4734 Yetani::VectorOutputId Yetani::outputVector() const noexcept
4735 {
4736  Yetani::VectorOutputId vector;
4737 
4738  std::lock_guard<std::mutex> lock(output_data.mutex);
4739 
4740  for(const auto& iter : output_data.outputid_to_wloutput)
4741  {
4742  vector.push_back(iter.first);
4743  }
4744 
4745  return vector;
4746 }
4747 
4748 
4760 std::string Yetani::outputSubpixelName(int32_t subpixel_format
4761  ) noexcept
4762 {
4763  switch(subpixel_format)
4764  {
4765 #define X(value_, name_) \
4766  case value_: return name_;
4767  ZAKERO_YETANI__OUTPUT_SUBPIXEL
4768 #undef X
4769  default: return "";
4770  }
4771 }
4772 
4773 
4785 std::string Yetani::outputTransformName(int32_t transform
4786  ) noexcept
4787 {
4788  switch(transform)
4789  {
4790 #define X(value_, name_) \
4791  case value_: return name_;
4792  ZAKERO_YETANI__OUTPUT_TRANSFORM
4793 #undef X
4794  default: return "";
4795  }
4796 }
4797 
4798 
4809 Yetani::PointMm Yetani::outputConvertToMm(const Yetani::OutputId output_id
4810  , const Yetani::PointPixel& point
4811  ) const noexcept
4812 {
4813  std::lock_guard<std::mutex> lock(output_data.mutex);
4814 
4815  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4816  {
4817  return { point.time, 0, 0 };
4818  }
4819 
4820  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4821  const Yetani::Output& output = output_data.output_map.at(wl_output);
4822 
4823  auto p = convertPixelToMm(output, point.x, point.y);
4824 
4825  return { point.time, p.first, p.second };
4826 }
4827 
4828 
4839 Yetani::PointPercent Yetani::outputConvertToPercent(const Yetani::OutputId output_id
4840  , const Yetani::PointPixel& point
4841  ) const noexcept
4842 {
4843  std::lock_guard<std::mutex> lock(output_data.mutex);
4844 
4845  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4846  {
4847  return { point.time, 0, 0 };
4848  }
4849 
4850  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4851  const Yetani::Output& output = output_data.output_map.at(wl_output);
4852 
4853  auto p = convertPixelToPercent(output, point.x, point.y);
4854 
4855  return { point.time, p.first, p.second };
4856 }
4857 
4858 
4869 Yetani::PointPixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4870  , const Yetani::PointMm& point
4871  ) const noexcept
4872 {
4873  std::lock_guard<std::mutex> lock(output_data.mutex);
4874 
4875  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4876  {
4877  return { point.time, 0, 0 };
4878  }
4879 
4880  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4881  const Yetani::Output& output = output_data.output_map.at(wl_output);
4882 
4883  auto p = convertMmToPixel(output, point.x, point.y);
4884 
4885  return { point.time, p.first, p.second };
4886 }
4887 
4888 
4899 Yetani::PointPixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4900  , const Yetani::PointPercent& point
4901  ) const noexcept
4902 {
4903  std::lock_guard<std::mutex> lock(output_data.mutex);
4904 
4905  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4906  {
4907  return { point.time, 0, 0 };
4908  }
4909 
4910  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4911  const Yetani::Output& output = output_data.output_map.at(wl_output);
4912 
4913  auto p = convertPercentToPixel(output, point.x, point.y);
4914 
4915  return { point.time, p.first, p.second };
4916 }
4917 
4918 
4929 Yetani::SizeMm Yetani::outputConvertToMm(const Yetani::OutputId output_id
4930  , const Yetani::SizePixel& size
4931  ) const noexcept
4932 {
4933  std::lock_guard<std::mutex> lock(output_data.mutex);
4934 
4935  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4936  {
4937  return { 0, 0 };
4938  }
4939 
4940  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4941  const Yetani::Output& output = output_data.output_map.at(wl_output);
4942 
4943  auto p = convertPixelToMm(output, size.width, size.height);
4944 
4945  return { p.first, p.second };
4946 }
4947 
4948 
4959 Yetani::SizePercent Yetani::outputConvertToPercent(const Yetani::OutputId output_id
4960  , const Yetani::SizePixel& size
4961  ) const noexcept
4962 {
4963  std::lock_guard<std::mutex> lock(output_data.mutex);
4964 
4965  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4966  {
4967  return { 0, 0 };
4968  }
4969 
4970  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4971  const Yetani::Output& output = output_data.output_map.at(wl_output);
4972 
4973  auto p = convertPixelToPercent(output, size.width, size.height);
4974 
4975  return { p.first, p.second };
4976 }
4977 
4978 
4988 Yetani::SizePixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4989  , const Yetani::SizeMm& size
4990  ) const noexcept
4991 {
4992  std::lock_guard<std::mutex> lock(output_data.mutex);
4993 
4994  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4995  {
4996  return { 0, 0 };
4997  }
4998 
4999  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
5000  const Yetani::Output& output = output_data.output_map.at(wl_output);
5001 
5002  auto p = convertMmToPixel(output, size.width, size.height);
5003 
5004  return { p.first, p.second };
5005 }
5006 
5007 
5017 Yetani::SizePixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
5018  , const Yetani::SizePercent& size
5019  ) const noexcept
5020 {
5021  std::lock_guard<std::mutex> lock(output_data.mutex);
5022 
5023  if(output_data.outputid_to_wloutput.contains(output_id) == false)
5024  {
5025  return { 0, 0 };
5026  }
5027 
5028  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
5029  const Yetani::Output& output = output_data.output_map.at(wl_output);
5030 
5031  auto p = convertPercentToPixel(output, size.width, size.height);
5032 
5033  return { p.first, p.second };
5034 }
5035 
5036 
5046 void Yetani::outputOnAdd(LambdaOutputId lambda
5047  ) noexcept
5048 {
5049  if(lambda == nullptr)
5050  {
5051  on_output_add = LambdaOutputId_DoNothing;
5052  }
5053  else
5054  {
5055  on_output_add = lambda;
5056  }
5057 }
5058 
5059 
5069 void Yetani::outputOnChange(LambdaOutputId lambda
5070  ) noexcept
5071 {
5072  if(lambda == nullptr)
5073  {
5074  on_output_change = LambdaOutputId_DoNothing;
5075  }
5076  else
5077  {
5078  on_output_change = lambda;
5079  }
5080 }
5081 
5082 
5092 void Yetani::outputOnRemove(LambdaOutputId lambda
5093  ) noexcept
5094 {
5095  if(lambda == nullptr)
5096  {
5097  on_output_remove = LambdaOutputId_DoNothing;
5098  }
5099  else
5100  {
5101  on_output_remove = lambda;
5102  }
5103 }
5104 
5105 
5114 void Yetani::convertPixel(struct wl_surface* wl_surface
5115  , const int32_t pixel_xw
5116  , const int32_t pixel_yh
5117  , float& mm_xw
5118  , float& mm_yh
5119  , float& pc_xw
5120  , float& pc_yh
5121  ) const noexcept
5122 {
5123  std::lock_guard<std::mutex> lock(output_data.mutex);
5124 
5125  const Yetani::VectorWlOutput& vector = output_data.surface_output_map.at(wl_surface);
5126  struct wl_output* wl_output = vector.front();
5127  const Yetani::Output& output = output_data.output_map.at(wl_output);
5128 
5129  auto mm = convertPixelToMm(output, pixel_xw, pixel_yh);
5130  mm_xw = mm.first;
5131  mm_yh = mm.second;
5132 
5133  auto pc = convertPixelToPercent(output, pixel_xw, pixel_yh);
5134  pc_xw = pc.first;
5135  pc_yh = pc.second;
5136 }
5137 
5138 
5150 std::pair<float, float> Yetani::convertPixelToMm(const Yetani::Output& output
5151  , int32_t xw
5152  , int32_t yh
5153  ) const noexcept
5154 {
5155  const float ratio_h = output.pixels_per_mm_horizontal;
5156  const float ratio_v = output.pixels_per_mm_vertical;
5157 
5158  return
5159  { xw / ratio_h
5160  , yh / ratio_v
5161  };
5162 }
5163 
5164 
5176 std::pair<float, float> Yetani::convertPixelToPercent(const Yetani::Output& output
5177  , int32_t xw
5178  , int32_t yh
5179  ) const noexcept
5180 {
5181  return
5182  { float(xw) / output.width
5183  , float(yh) / output.height
5184  };
5185 }
5186 
5187 
5199 std::pair<int32_t, int32_t> Yetani::convertMmToPixel(const Yetani::Output& output
5200  , float xw
5201  , float yh
5202  ) const noexcept
5203 {
5204  const float ratio_h = output.pixels_per_mm_horizontal;
5205  const float ratio_v = output.pixels_per_mm_vertical;
5206 
5207  return
5208  { int32_t(xw * ratio_h)
5209  , int32_t(yh * ratio_v)
5210  };
5211 }
5212 
5213 
5225 std::pair<int32_t, int32_t> Yetani::convertPercentToPixel(const Yetani::Output& output
5226  , float xw
5227  , float yh
5228  ) const noexcept
5229 {
5230  return
5231  { int32_t(xw * output.width)
5232  , int32_t(yh * output.height)
5233  };
5234 }
5235 
5236 
5248 void Yetani::outputNotifySurface(Yetani* yetani
5249  , struct wl_output* wl_output
5250  , struct wl_surface* wl_surface
5251  ) noexcept
5252 {
5253  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
5254  if(surface_extent.preferred_unit == Yetani::SizeUnit::Pixel)
5255  {
5256  return;
5257  }
5258 
5259  Yetani::OutputData& output_data = yetani->output_data;
5260 
5261  std::lock_guard<std::mutex> lock(output_data.mutex);
5262 
5263  Yetani::VectorWlOutput& output_vector = output_data.surface_output_map[wl_surface];
5264 
5265  struct wl_output* output_current = output_vector.front();
5266 
5267  if(output_current != wl_output)
5268  {
5269  return;
5270  }
5271 
5272  Yetani::Output& output = output_data.output_map.at(wl_output);
5273  Yetani::SizePixel new_size = surface_extent.size_pixel;
5274 
5275  if(surface_extent.preferred_unit == Yetani::SizeUnit::Millimeter)
5276  {
5277  auto p = yetani->convertMmToPixel(output, surface_extent.size_mm.width, surface_extent.size_mm.height);
5278  new_size = { p.first, p.second };
5279  }
5280  else if(surface_extent.preferred_unit == Yetani::SizeUnit::Percent)
5281  {
5282  auto p = yetani->convertPercentToPixel(output, surface_extent.size_percent.width, surface_extent.size_percent.height);
5283  new_size = { p.first, p.second };
5284  }
5285 
5286  if(new_size.width <= 0)
5287  {
5288  new_size.width = 1;
5289  }
5290 
5291  if(new_size.height <= 0)
5292  {
5293  new_size.height = 1;
5294  }
5295 
5296  yetani->surface_resize_mutex_map[wl_surface].lock();
5297  {
5298  surface_extent.size_pixel = new_size;
5299  surfaceCalculateSize(yetani, wl_surface, new_size);
5300  }
5301  yetani->surface_resize_mutex_map[wl_surface].unlock();
5302 }
5303 
5304 // }}}
5305 // {{{ Wayland : Seat
5306 
5339 void Yetani::seatDestroy(struct wl_seat*& wl_seat
5340  ) noexcept
5341 {
5342  Yetani::Seat& seat = seat_map[wl_seat];
5343 
5344  if(seat.wl_keyboard != nullptr)
5345  {
5346  wl_keyboard_release(seat.wl_keyboard);
5347  seat.wl_keyboard = nullptr;
5348  }
5349 
5350  if(seat.wl_pointer != nullptr)
5351  {
5352  wl_pointer_release(seat.wl_pointer);
5353  seat.wl_pointer = nullptr;
5354  }
5355 
5356  if(seat.wl_touch != nullptr)
5357  {
5358  wl_touch_release(seat.wl_touch);
5359  seat.wl_touch = nullptr;
5360  }
5361 
5362  seat_map.erase(wl_seat);
5363 
5364  wl_seat_release(wl_seat);
5365 
5366  wl_seat = nullptr;
5367 }
5368 
5369 // }}}
5370 // {{{ Wayland : Seat : Keyboard
5371 
5445 int32_t Yetani::keyRepeatDelay() const noexcept
5446 {
5447  return keyboard.repeat_delay;
5448 }
5449 
5450 
5459 int32_t Yetani::keyRepeatRate() const noexcept
5460 {
5461  return 1000 / keyboard.repeat_rate;
5462 }
5463 
5464 
5468 void Yetani::keyboardDestroy(Yetani::Keyboard& keyboard
5469  ) noexcept
5470 {
5471  if(keyboard.keymap != nullptr)
5472  {
5473  munmap(keyboard.keymap, keyboard.keymap_size);
5474  }
5475 
5476  keyboard.wl_surface = nullptr;
5477  keyboard.event = nullptr;
5478  keyboard.modifier = { 0 };
5479  keyboard.repeat_rate = 0;
5480  keyboard.repeat_delay = {};
5481  keyboard.keymap = nullptr;
5482  keyboard.keymap_size = 0;
5483 }
5484 
5485 
5492 void Yetani::keyboardRepeat(Yetani::Keyboard& keyboard
5493  ) noexcept
5494 {
5495  auto now = std::chrono::steady_clock::now();
5496 
5497  for(auto& iter : keyboard.repeat_map)
5498  {
5499  Yetani::KeyRepeatData& key_repeat = iter.second;
5500 
5501  if(now >= key_repeat.trigger_time)
5502  {
5503  uint32_t key_code = iter.first;
5504 
5505  Yetani::Key key =
5506  { .time = key_repeat.base_time
5507  , .code = key_code
5508  , .state = Yetani::KeyState::Repeat
5509  };
5510 
5511  keyboard.event->on_key(key, keyboard.modifier);
5512 
5513  key_repeat.trigger_time = now
5514  + std::chrono::milliseconds(keyboard.repeat_rate)
5515  - (now - key_repeat.trigger_time)
5516  ;
5517  key_repeat.base_time += keyboard.repeat_rate;
5518  }
5519  }
5520 }
5521 
5522 
5530 void Yetani::keyboardRepeatAdd(Yetani::Keyboard& keyboard
5531  , uint32_t key_code
5532  , uint32_t time
5533  ) noexcept
5534 {
5535  auto trigger_time = std::chrono::steady_clock::now()
5536  + std::chrono::milliseconds(keyboard.repeat_delay)
5537  ;
5538 
5539  keyboard.repeat_map[key_code] =
5540  { .trigger_time = trigger_time
5541  , .base_time = time + keyboard.repeat_delay
5542  };
5543 }
5544 
5545 
5552 void Yetani::keyboardRepeatReleaseAll(Yetani::Keyboard& keyboard
5553  ) noexcept
5554 {
5555  while(keyboard.repeat_map.empty() == false)
5556  {
5557  auto iter = keyboard.repeat_map.begin();
5558 
5559  uint32_t key_code = iter->first;
5560 
5561  Yetani::Key key =
5562  { .time = 0
5563  , .code = key_code
5564  , .state = Yetani::KeyState::Released
5565  };
5566 
5567  keyboard.event->on_key(key, keyboard.modifier);
5568 
5569  keyboard.repeat_map.erase(iter);
5570  }
5571 }
5572 
5573 
5580 void Yetani::keyboardRepeatRemove(Yetani::Keyboard& keyboard
5581  , uint32_t key_code
5582  ) noexcept
5583 {
5584  keyboard.repeat_map.erase(key_code);
5585 }
5586 
5587 // }}}
5588 // {{{ Wayland : Seat : Pointer
5589 
5605 void Yetani::pointerClear(Yetani::Pointer& pointer
5606  ) noexcept
5607 {
5608  pointer.enter_surface = nullptr;
5609  pointer.enter_point = { 0, 0, 0 };
5610  pointer.leave_surface = nullptr;
5611  pointer.motion_point = { 0, 0, 0 };
5612  pointer.button_event_code = 0;
5613  pointer.button_is_pressed = false;
5614  pointer.button_time = 0;
5615  pointer.axis.time = 0;
5616  pointer.axis.type = Yetani::PointerAxisType::Unknown;
5617  pointer.axis.distance = 0;
5618  pointer.axis.source = Yetani::PointerAxisSource::Unknown;
5619  pointer.axis.steps = 0;
5620 }
5621 
5622 // }}}
5623 // {{{ Wayland : Surface
5624 
5662 void Yetani::surfaceCalculateSize(Yetani* yetani
5663  , struct wl_surface* wl_surface
5664  , const Yetani::SizePixel& size
5665  ) noexcept
5666 {
5667  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
5668  surface_size.width = size.width;
5669  surface_size.height = size.height;
5670  surface_size.stride = size.width * surface_size.bytes_per_pixel;
5671  surface_size.in_bytes = surface_size.stride * surface_size.height;
5672 
5673  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5674  surface_frame.width = size.width;
5675  surface_frame.height = size.height;
5676 }
5677 
5678 
5696 struct wl_surface* Yetani::surfaceCreate(Yetani* yetani
5697  , const wl_shm_format pixel_format
5698  , const Yetani::SizePixel& size
5699  , Yetani::Window::Memory& window_memory
5700  ) noexcept
5701 {
5702  struct wl_surface* wl_surface = wl_compositor_create_surface(yetani->compositor);
5703 
5704  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
5705  surface_size.pixel_format = pixel_format;
5706  surface_size.bytes_per_pixel = shmFormatBytesPerPixel(pixel_format);
5707 
5708  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5709  surface_frame.wl_surface = wl_surface;
5710  surface_frame.time_ms = 0;
5711 
5712  surfaceCalculateSize(yetani, wl_surface, size);
5713 
5714  surface_frame.buffer_next = bufferCreate(surface_size, &window_memory, &yetani->buffer);
5715 
5716  // A future configuration setting
5717  bool event_keyboard = true;
5718  if(event_keyboard)
5719  {
5720  yetani->keyboard.event_map[wl_surface] =
5721  { .on_enter = Lambda_DoNothing
5722  , .on_leave = Lambda_DoNothing
5723  , .on_key = LambdaKey_DoNothing
5724  };
5725  }
5726 
5727  // A future configuration setting
5728  bool event_pointer = true;
5729  if(event_pointer)
5730  {
5731  yetani->pointer.event_map[wl_surface] =
5732  { .on_axis = LambdaAxis_DoNothing
5733  , .on_axis_discrete = Lambda_DoNothing
5734  , .on_axis_source = Lambda_DoNothing
5735  , .on_axis_stop = Lambda_DoNothing
5736  , .on_button_mm = LambdaButtonMm_DoNothing
5737  , .on_button_percent = LambdaButtonPercent_DoNothing
5738  , .on_button_pixel = LambdaButtonPixel_DoNothing
5739  , .on_enter_mm = LambdaPointMm_DoNothing
5740  , .on_enter_percent = LambdaPointPercent_DoNothing
5741  , .on_enter_pixel = LambdaPointPixel_DoNothing
5742  , .on_leave = Lambda_DoNothing
5743  , .on_motion_mm = LambdaPointMm_DoNothing
5744  , .on_motion_percent = LambdaPointPercent_DoNothing
5745  , .on_motion_pixel = LambdaPointPixel_DoNothing
5746  };
5747  }
5748 
5749  yetani->surface_event_map[wl_surface] =
5750  { .on_size_mm_change = LambdaSizeMm_DoNothing
5751  , .on_size_percent_change = LambdaSizePercent_DoNothing
5752  , .on_size_pixel_change = LambdaSizePixel_DoNothing
5753  };
5754 
5755  wl_surface_add_listener(wl_surface
5756  , &surface_listener
5757  , yetani
5758  );
5759 
5760  return wl_surface;
5761 }
5762 
5763 
5769 void Yetani::surfaceDestroy(Yetani* yetani
5770  , struct wl_surface*& wl_surface
5771  ) noexcept
5772 {
5773  if(wl_surface == nullptr)
5774  {
5775  return;
5776  }
5777 
5778  if(yetani->surface_frame_map.contains(wl_surface))
5779  {
5780  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5781 
5782  struct wl_buffer* wl_buffer = nullptr;
5783  wl_buffer = surface_frame.buffer_next.exchange(nullptr);
5784 
5785  if(wl_buffer != nullptr)
5786  {
5787  bufferDestroy(wl_buffer);
5788  }
5789  }
5790 
5791  if(yetani->keyboard.event_map.contains(wl_surface))
5792  {
5793  yetani->keyboard.event_map.erase(wl_surface);
5794  }
5795 
5796  if(yetani->pointer.event_map.contains(wl_surface))
5797  {
5798  yetani->pointer.event_map.erase(wl_surface);
5799  }
5800 
5801  yetani->surface_size_map.erase(wl_surface);
5802  yetani->surface_frame_map.erase(wl_surface);
5803  yetani->surface_event_map.erase(wl_surface);
5804 
5805  yetani->cursorDetach(wl_surface);
5806 
5807  wl_surface_destroy(wl_surface);
5808  wl_surface = nullptr;
5809 }
5810 
5811 // }}}
5812 // {{{ Wayland : Listener Handlers : Buffer
5813 
5826 void Yetani::handlerBufferRelease(void* //data
5827  , struct wl_buffer* wl_buffer
5828  ) noexcept
5829 {
5830  Yetani::bufferDestroy(wl_buffer);
5831 }
5832 
5833 // }}}
5834 // {{{ Wayland : Listener Handlers : Keyboard
5835 
5839 void Yetani::handlerKeyboardEnter(void* data
5840  , struct wl_keyboard* // wl_keyboard
5841  , uint32_t // serial
5842  , struct wl_surface* wl_surface
5843  , struct wl_array* key_array
5844  ) noexcept
5845 {
5846  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5847 
5848  if(keyboard.wl_surface != nullptr)
5849  {
5850  keyboardRepeatReleaseAll(keyboard);
5851 
5852  keyboard.event->on_leave();
5853  }
5854 
5855  keyboard.wl_surface = wl_surface;
5856 
5857  if(keyboard.event_map.contains(wl_surface))
5858  {
5859  keyboard.event = &(keyboard.event_map[wl_surface]);
5860  }
5861  else
5862  {
5863  keyboard.event = &(keyboard.event_map[nullptr]);
5864  }
5865 
5866  keyboard.event->on_enter();
5867 
5868  if(key_array->size > 0)
5869  {
5870  Yetani::Key key =
5871  { .time = 0
5872  , .code = 0
5873  , .state = Yetani::KeyState::Pressed
5874  };
5875 
5876  ZAKERO_YETANI__ARRAY_FOR_EACH(uint32_t*, key_iter, key_array)
5877  {
5878  key.code = *key_iter;
5879 
5880  keyboard.event->on_key(key, keyboard.modifier);
5881 
5882  keyboardRepeatAdd(keyboard, key.code, 0);
5883  }
5884  }
5885 }
5886 
5887 
5891 void Yetani::handlerKeyboardKey(void* data
5892  , struct wl_keyboard* // wl_keyboard
5893  , uint32_t // serial
5894  , uint32_t time
5895  , uint32_t key_code
5896  , uint32_t state
5897  ) noexcept
5898 {
5899  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5900 
5901  Yetani::Key key =
5902  { .time = time
5903  , .code = key_code
5904  , .state = (state == WL_KEYBOARD_KEY_STATE_PRESSED)
5905  ? Yetani::KeyState::Pressed
5906  : Yetani::KeyState::Released
5907  };
5908 
5909  keyboard.event->on_key(key, keyboard.modifier);
5910 
5911  if(key.state == Yetani::KeyState::Pressed
5912  && keyboard.repeat_rate > 0
5913  )
5914  {
5915  keyboardRepeatAdd(keyboard, key_code, time);
5916  }
5917  else if(key.state == Yetani::KeyState::Released)
5918  {
5919  keyboardRepeatRemove(keyboard, key_code);
5920  }
5921 }
5922 
5923 
5927 void Yetani::handlerKeyboardKeymap(void* data
5928  , struct wl_keyboard* // wl_keyboard
5929  , uint32_t format
5930  , int32_t fd
5931  , uint32_t size
5932  ) noexcept
5933 {
5934  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5935 
5936  if(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
5937  {
5938  if(keyboard.keymap != nullptr)
5939  {
5940  munmap(keyboard.keymap
5941  , keyboard.keymap_size
5942  );
5943  }
5944 
5945  keyboard.keymap = (char*)mmap(nullptr
5946  , size
5947  , PROT_READ
5948  , MAP_NORESERVE | MAP_PRIVATE
5949  , fd
5950  , 0
5951  );
5952  keyboard.keymap_size = size;
5953  }
5954  else // (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP)
5955  {
5956  if(keyboard.keymap != nullptr)
5957  {
5958  munmap(keyboard.keymap
5959  , keyboard.keymap_size
5960  );
5961 
5962  keyboard.keymap = nullptr;
5963  keyboard.keymap_size = 0;
5964  }
5965  }
5966 }
5967 
5968 
5972 void Yetani::handlerKeyboardLeave(void* data
5973  , struct wl_keyboard* // wl_keyboard
5974  , uint32_t // serial
5975  , struct wl_surface* wl_surface
5976  ) noexcept
5977 {
5978  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5979 
5980  if(keyboard.wl_surface == wl_surface)
5981  {
5982  keyboardRepeatReleaseAll(keyboard);
5983 
5984  keyboard.event->on_leave();
5985 
5986  keyboard.event = &(keyboard.event_map[nullptr]);
5987  keyboard.wl_surface = nullptr;
5988  }
5989 }
5990 
5991 
5995 void Yetani::handlerKeyboardModifiers(void* data
5996  , struct wl_keyboard* // wl_keyboard
5997  , uint32_t // serial
5998  , uint32_t mods_pressed
5999  , uint32_t mods_latched
6000  , uint32_t mods_locked
6001  , uint32_t group
6002  ) noexcept
6003 {
6004  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
6005 
6006  keyboard.modifier.pressed = mods_pressed;
6007  keyboard.modifier.latched = mods_latched;
6008  keyboard.modifier.locked = mods_locked;
6009  keyboard.modifier.group = group;
6010 }
6011 
6012 
6016 void Yetani::handlerKeyboardRepeatInfo(void* data
6017  , struct wl_keyboard* // wl_keyboard
6018  , int32_t rate
6019  , int32_t delay
6020  ) noexcept
6021 {
6022  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
6023 
6024  keyboard.repeat_delay = delay;
6025  keyboard.repeat_rate = 1000 / rate;
6026 }
6027 
6028 // }}}
6029 // {{{ Wayland : Listener Handlers : Output
6030 
6034 void Yetani::handlerOutputDone(void* data
6035  , struct wl_output* wl_output
6036  ) noexcept
6037 {
6038  Yetani* yetani = (Yetani*)data;
6039  Yetani::Output& output = yetani->output_data.output_map[wl_output];
6040  Yetani::Output& changes = yetani->output_changes_map[wl_output];
6041  Yetani::OutputId output_id = yetani->output_data.wloutput_to_outputid[wl_output];
6042 
6070  output = changes;
6071  output.pixels_per_mm_horizontal = output.width / float(output.physical_width_mm);
6072  output.pixels_per_mm_vertical = output.height / float(output.physical_height_mm);
6073 
6074  ZAKERO_YETANI__DEBUG << "\n" << to_string(output) << "\n";
6075 
6076  switch(yetani->output_state_map[wl_output])
6077  {
6078  case Yetani::OutputState::Done:
6079  // Do Nothing
6080  break;
6081 
6082  case Yetani::OutputState::Added:
6083  yetani->on_output_add(output_id);
6084  break;
6085 
6086  case Yetani::OutputState::Changed:
6087  yetani->on_output_change(output_id);
6088 
6089  for(auto wl_surface : yetani->output_notify_surface_vector)
6090  {
6091  outputNotifySurface(yetani, wl_output, wl_surface);
6092  }
6093 
6094  break;
6095  }
6096 
6097  yetani->output_state_map[wl_output] = Yetani::OutputState::Done;
6098 }
6099 
6100 
6104 void Yetani::handlerOutputGeometry(void* data
6105  , struct wl_output* wl_output
6106  , int32_t x
6107  , int32_t y
6108  , int32_t physical_width
6109  , int32_t physical_height
6110  , int32_t subpixel
6111  , const char* make
6112  , const char* model
6113  , int32_t transform
6114  ) noexcept
6115 {
6116  Yetani* yetani = (Yetani*)data;
6117  Yetani::Output& output_changes = yetani->output_changes_map[wl_output];
6118 
6119  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6120  {
6121  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6122  }
6123 
6124  output_changes.x = x;
6125  output_changes.y = y;
6126  output_changes.physical_width_mm = physical_width;
6127  output_changes.physical_height_mm = physical_height;
6128  output_changes.subpixel = subpixel;
6129  output_changes.make = std::string(make);
6130  output_changes.model = std::string(model);
6131  output_changes.transform = transform;
6132 }
6133 
6134 
6138 void Yetani::handlerOutputMode(void* data
6139  , struct wl_output* wl_output
6140  , uint32_t flags
6141  , int32_t width
6142  , int32_t height
6143  , int32_t refresh
6144  ) noexcept
6145 {
6146  Yetani* yetani = (Yetani*)data;
6147  Yetani::Output& output_changes = yetani->output_changes_map[wl_output];
6148 
6149  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6150  {
6151  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6152  }
6153 
6154  output_changes.flags = flags;
6155  output_changes.width = width;
6156  output_changes.height = height;
6157  output_changes.refresh_mHz = refresh;
6158 }
6159 
6160 
6164 void Yetani::handlerOutputScale(void* data
6165  , struct wl_output* wl_output
6166  , int32_t factor
6167  ) noexcept
6168 {
6169  Yetani* yetani = (Yetani*)data;
6170  Output& output_changes = yetani->output_changes_map[wl_output];
6171 
6172  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6173  {
6174  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6175  }
6176 
6177  output_changes.scale_factor = factor;
6178 }
6179 
6180 // }}}
6181 // {{{ Wayland : Listener Handlers : Pointer
6182 
6186 void Yetani::handlerPointerAxis(void* data
6187  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6188  , uint32_t time
6189  , uint32_t axis
6190  , wl_fixed_t value
6191  ) noexcept
6192 {
6193  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6194 
6195  pointer.axis.time = time;
6196  pointer.axis.distance = (float)wl_fixed_to_double(value);
6197 
6198  if(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
6199  {
6200  pointer.axis.type = Yetani::PointerAxisType::Horizontal;
6201  }
6202  else if(axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
6203  {
6204  pointer.axis.type = Yetani::PointerAxisType::Vertical;
6205  }
6206  else
6207  {
6208  pointer.axis.type = Yetani::PointerAxisType::Unknown;
6209  }
6210 }
6211 
6212 
6216 void Yetani::handlerPointerAxisDiscrete(void* data
6217  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6218  , uint32_t //axis ///< The axis
6219  , int32_t discrete
6220  ) noexcept
6221 {
6222  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6223 
6224  pointer.axis.steps = discrete;
6225 }
6226 
6227 
6231 void Yetani::handlerPointerAxisSource(void* data
6232  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6233  , uint32_t axis_source
6234  ) noexcept
6235 {
6236  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6237 
6238  switch(axis_source)
6239  {
6240  case WL_POINTER_AXIS_SOURCE_WHEEL:
6241  pointer.axis.source = Yetani::PointerAxisSource::Wheel;
6242  break;
6243 
6244  case WL_POINTER_AXIS_SOURCE_FINGER:
6245  pointer.axis.source = Yetani::PointerAxisSource::Finger;
6246  break;
6247 
6248  case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
6249  pointer.axis.source = Yetani::PointerAxisSource::Continuous;
6250  break;
6251 
6252  case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
6253  pointer.axis.source = Yetani::PointerAxisSource::Wheel_Tilt;
6254  break;
6255 
6256  default:
6257  pointer.axis.source = Yetani::PointerAxisSource::Unknown;
6258  }
6259 }
6260 
6261 
6265 void Yetani::handlerPointerAxisStop(void*
6266  , struct wl_pointer*
6267  , uint32_t
6268  , uint32_t
6269  ) noexcept
6270 {
6271  // --- Ignored ---
6272  //
6273  // Wayland documentation suggests that the "axis stop" can be used for
6274  // kinetic scrolling or to determine when one axis motions begins anew.
6275  //
6276  // This is not needed.
6277  // - For kinetic scrolling: Have the default scrolling be kinetic and
6278  // treat axis input as a new (or additive) velocity.
6279  // - For separation of axis motion, why? If there is a pause in the
6280  // motion, that reflects the user input.
6281 }
6282 
6283 
6287 void Yetani::handlerPointerButton(void* data
6288  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6289  , uint32_t //serial ///< The Event Id
6290  , uint32_t time
6291  , uint32_t button
6292  , uint32_t state
6293  ) noexcept
6294 {
6295  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6296 
6297  pointer.button.code = button;
6298  pointer.button_time = time;
6299 
6300  if(state == WL_POINTER_BUTTON_STATE_RELEASED)
6301  {
6302  pointer.button.state = Yetani::PointerButtonState::Released;
6303  }
6304  else if(state == WL_POINTER_BUTTON_STATE_PRESSED)
6305  {
6306  pointer.button.state = Yetani::PointerButtonState::Pressed;
6307  }
6308 }
6309 
6310 
6314 void Yetani::handlerPointerEnter(void* data
6315  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6316  , uint32_t serial
6317  , struct wl_surface* wl_surface
6318  , wl_fixed_t surface_x
6319  , wl_fixed_t surface_y
6320  ) noexcept
6321 {
6322  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6323 
6324  pointer.enter_serial = serial;
6325  pointer.enter_surface = wl_surface;
6326 
6327  pointer.enter_point =
6328  { .time = 0
6329  , .x = wl_fixed_to_int(surface_x)
6330  , .y = wl_fixed_to_int(surface_y)
6331  };
6332 }
6333 
6334 
6338 void Yetani::handlerPointerFrame(void* data
6339  , struct wl_pointer* wl_pointer
6340  ) noexcept
6341 {
6342  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6343  Yetani* yetani = pointer.yetani;
6344 
6345  if(pointer.enter_surface != nullptr)
6346  {
6347  if(pointer.wl_surface != nullptr)
6348  {
6349  yetani->cursorLeave(pointer.wl_surface);
6350  pointer.event_map[pointer.wl_surface].on_leave();
6351  }
6352 
6353  yetani->cursorEnter(wl_pointer
6354  , pointer.enter_serial
6355  , pointer.enter_surface
6356  );
6357 
6358  pointer.wl_surface = pointer.enter_surface;
6359  pointer.point_pixel = pointer.enter_point;
6360 
6361  if(pointer.event_map.contains(pointer.wl_surface))
6362  {
6363  pointer.event = &(pointer.event_map[pointer.wl_surface]);
6364  }
6365  else
6366  {
6367  pointer.event = &(pointer.event_map[nullptr]);
6368  }
6369 
6370  yetani->convertPixel(pointer.enter_surface
6371  , pointer.point_pixel.x , pointer.point_pixel.y
6372  , pointer.point_mm.x , pointer.point_mm.y
6373  , pointer.point_percent.x, pointer.point_percent.y
6374  );
6375 
6376  pointer.event->on_enter_pixel(pointer.point_pixel
6377  , yetani->keyboard.modifier
6378  );
6379  pointer.event->on_enter_mm(pointer.point_mm
6380  , yetani->keyboard.modifier
6381  );
6382  pointer.event->on_enter_percent(pointer.point_percent
6383  , yetani->keyboard.modifier
6384  );
6385  }
6386 
6387  if((pointer.motion_point.time != 0)
6388  && (pointer.wl_surface != nullptr)
6389  )
6390  {
6391  pointer.point_pixel = pointer.motion_point;
6392 
6393  yetani->convertPixel(pointer.wl_surface
6394  , pointer.point_pixel.x , pointer.point_pixel.y
6395  , pointer.point_mm.x , pointer.point_mm.y
6396  , pointer.point_percent.x, pointer.point_percent.y
6397  );
6398  pointer.point_mm.time = pointer.point_pixel.time;
6399  pointer.point_percent.time = pointer.point_pixel.time;
6400 
6401  pointer.event->on_motion_pixel(pointer.point_pixel
6402  , yetani->keyboard.modifier
6403  );
6404  pointer.event->on_motion_mm(pointer.point_mm
6405  , yetani->keyboard.modifier
6406  );
6407  pointer.event->on_motion_percent(pointer.point_percent
6408  , yetani->keyboard.modifier
6409  );
6410  }
6411 
6412  if((pointer.button_time != 0)
6413  && (pointer.wl_surface != nullptr)
6414  )
6415  {
6416  pointer.point_mm.time = pointer.button_time;
6417  pointer.point_percent.time = pointer.button_time;
6418  pointer.point_pixel.time = pointer.button_time;
6419 
6420  pointer.event->on_button_pixel(pointer.button
6421  , pointer.point_pixel
6422  , yetani->keyboard.modifier
6423  );
6424  pointer.event->on_button_mm(pointer.button
6425  , pointer.point_mm
6426  , yetani->keyboard.modifier
6427  );
6428  pointer.event->on_button_percent(pointer.button
6429  , pointer.point_percent
6430  , yetani->keyboard.modifier
6431  );
6432  }
6433 
6434  if((pointer.axis.time != 0)
6435  && (pointer.wl_surface != nullptr)
6436  )
6437  {
6438  pointer.event->on_axis(pointer.axis
6439  , yetani->keyboard.modifier
6440  );
6441  }
6442 
6443  if((pointer.leave_surface != nullptr)
6444  && (pointer.leave_surface == pointer.wl_surface)
6445  )
6446  {
6447  yetani->cursorLeave(pointer.leave_surface);
6448 
6449  pointer.event->on_leave();
6450 
6451  pointer.event = &(pointer.event_map[nullptr]);
6452  pointer.wl_surface = nullptr;
6453  }
6454 
6455  pointerClear(pointer);
6456 }
6457 
6458 
6462 void Yetani::handlerPointerLeave(void* data
6463  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6464  , uint32_t //serial ///< The Event Id
6465  , struct wl_surface* wl_surface
6466  ) noexcept
6467 {
6468  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6469 
6470  pointer.leave_surface = wl_surface;
6471 }
6472 
6473 
6477 void Yetani::handlerPointerMotion(void* data
6478  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6479  , uint32_t time
6480  , wl_fixed_t surface_x
6481  , wl_fixed_t surface_y
6482  ) noexcept
6483 {
6484  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6485 
6486  pointer.motion_point =
6487  { .time = time
6488  , .x = wl_fixed_to_int(surface_x)
6489  , .y = wl_fixed_to_int(surface_y)
6490  };
6491 }
6492 
6493 // }}}
6494 // {{{ Wayland : Listener Handlers : Registry
6495 
6499 void Yetani::handlerRegistryGlobal(void* data
6500  , struct wl_registry* registry
6501  , uint32_t id
6502  , const char* interface
6503  , uint32_t version
6504  ) noexcept
6505 {
6506  Yetani* yetani = (Yetani*)data;
6507 
6508  std::string_view interface_name(interface);
6509  ZAKERO_YETANI__DEBUG_VAR(interface_name);
6510 
6511  if(interface_name == wl_compositor_interface.name)
6512  {
6513  yetani->compositor = (struct wl_compositor*)
6514  wl_registry_bind(registry
6515  , id
6516  , &wl_compositor_interface
6517  , 1
6518  );
6519 
6520  return;
6521  }
6522 
6523  if(interface_name == wl_output_interface.name)
6524  {
6525  struct wl_output* wl_output = (struct wl_output*)wl_registry_bind(registry
6526  , id
6527  , &wl_output_interface
6528  , 2
6529  );
6530 
6531  yetani->output_data.wloutput_to_outputid[wl_output] = id;
6532  yetani->output_data.outputid_to_wloutput[id] = wl_output;
6533  yetani->output_data.output_map[wl_output] = {};
6534  yetani->output_changes_map[wl_output] = {};
6535  yetani->output_state_map[wl_output] = Yetani::OutputState::Added;
6536 
6537  wl_output_add_listener(wl_output
6538  , &Yetani::output_listener
6539  , yetani
6540  );
6541 
6542  return;
6543  }
6544 
6545  if(interface_name == wl_seat_interface.name)
6546  {
6547  yetani->seat = (struct wl_seat*)
6548  wl_registry_bind(registry
6549  , id
6550  , &wl_seat_interface
6551  , version
6552  );
6553 
6554  yetani->id_to_seat[id] = yetani->seat;
6555 
6556  wl_seat_add_listener(yetani->seat
6557  , &yetani->seat_listener
6558  , yetani
6559  );
6560 
6561  return;
6562  }
6563 
6564  if(interface_name == wl_shm_interface.name)
6565  {
6566  yetani->shm = (struct wl_shm*)
6567  wl_registry_bind(registry
6568  , id
6569  , &wl_shm_interface
6570  , version
6571  );
6572 
6573  wl_shm_add_listener(yetani->shm
6574  , &yetani->shm_listener
6575  , yetani
6576  );
6577 
6578  return;
6579  }
6580 
6581  if(interface_name == xdg_wm_base_interface.name)
6582  {
6583  yetani->xdg_wm_base = (struct xdg_wm_base*)
6584  wl_registry_bind(registry
6585  , id
6586  , &xdg_wm_base_interface
6587  , 1
6588  );
6589 
6590  xdg_wm_base_add_listener(yetani->xdg_wm_base
6591  , &yetani->xdg_wm_base_listener
6592  , yetani
6593  );
6594  }
6595 
6596  if(interface_name == zxdg_decoration_manager_v1_interface.name)
6597  {
6598  yetani->decoration_manager = (struct zxdg_decoration_manager_v1*)
6599  wl_registry_bind(registry
6600  , id
6601  , &zxdg_decoration_manager_v1_interface
6602  , 1
6603  );
6604  ZAKERO_YETANI__DEBUG << "--- Using UNSTABLE Decoration Manager ---\n";
6605  }
6606 }
6607 
6608 
6612 void Yetani::handlerRegistryRemove(void* data
6613  , struct wl_registry* //registry ///< The registry object
6614  , uint32_t id
6615  ) noexcept
6616 {
6617  Yetani* yetani = (Yetani*)data;
6618 
6619  printf("Got a registry remove event for id %d\n", id);
6620 
6621  // Output
6622  {
6623  std::lock_guard<std::mutex> lock(yetani->output_data.mutex);
6624 
6625  if(yetani->output_data.outputid_to_wloutput.contains(id))
6626  {
6627  struct wl_output* wl_output = yetani->output_data.outputid_to_wloutput[id];
6628 
6629  yetani->output_data.outputid_to_wloutput.erase(id);
6630  yetani->output_data.wloutput_to_outputid.erase(wl_output);
6631 
6632  yetani->output_changes_map.erase(wl_output);
6633  yetani->output_state_map.erase(wl_output);
6634 
6635  yetani->on_output_remove(id);
6636  yetani->output_data.output_map.erase(wl_output);
6637 
6638  return;
6639  }
6640  }
6641 
6642  // Seat
6643  {
6644  if(yetani->id_to_seat.contains(id))
6645  {
6646  struct wl_seat* wl_seat = yetani->id_to_seat[id];
6647 
6648  yetani->seatDestroy(wl_seat);
6649 
6650  yetani->id_to_seat.erase(id);
6651  }
6652  }
6653 }
6654 
6655 // }}}
6656 // {{{ Wayland : Listener Handlers : Seat
6657 
6665 void Yetani::handlerSeatCapabilities(void* data
6666  , struct wl_seat* wl_seat
6667  , uint32_t capabilities
6668  ) noexcept
6669 {
6670  ZAKERO_YETANI__DEBUG_VAR((uint64_t)wl_seat);
6671 
6672  Yetani* yetani = (Yetani*)data;
6673  Yetani::Seat& seat = yetani->seat_map[wl_seat];
6674 
6675  seat.version = wl_seat_get_version(wl_seat);
6676 
6677  if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD)
6678  {
6679  ZAKERO_YETANI__DEBUG << "-- Got a keyboard device --\n";
6680 
6681  yetani->keyboard.event_map[nullptr] =
6682  { .on_enter = Lambda_DoNothing
6683  , .on_leave = Lambda_DoNothing
6684  , .on_key = LambdaKey_DoNothing
6685  };
6686 
6687  yetani->keyboard.event = &(yetani->keyboard.event_map[nullptr]);
6688 
6689  seat.wl_keyboard = wl_seat_get_keyboard(wl_seat);
6690 
6691  wl_keyboard_add_listener(seat.wl_keyboard
6692  , &Yetani::keyboard_listener
6693  , &yetani->keyboard
6694  );
6695  }
6696 
6697  if(capabilities & WL_SEAT_CAPABILITY_POINTER)
6698  {
6699  ZAKERO_YETANI__DEBUG << "-- Got a pointer device --\n";
6700 
6701  yetani->pointer.yetani = yetani;
6702 
6703  yetani->pointer.event_map[nullptr] =
6704  { .on_axis = LambdaAxis_DoNothing
6705  , .on_axis_discrete = Lambda_DoNothing
6706  , .on_axis_source = Lambda_DoNothing
6707  , .on_axis_stop = Lambda_DoNothing
6708  , .on_button_mm = LambdaButtonMm_DoNothing
6709  , .on_button_percent = LambdaButtonPercent_DoNothing
6710  , .on_button_pixel = LambdaButtonPixel_DoNothing
6711  , .on_enter_mm = LambdaPointMm_DoNothing
6712  , .on_enter_percent = LambdaPointPercent_DoNothing
6713  , .on_enter_pixel = LambdaPointPixel_DoNothing
6714  , .on_leave = Lambda_DoNothing
6715  , .on_motion_mm = LambdaPointMm_DoNothing
6716  , .on_motion_percent = LambdaPointPercent_DoNothing
6717  , .on_motion_pixel = LambdaPointPixel_DoNothing
6718  };
6719 
6720  yetani->pointer.event = &(yetani->pointer.event_map[nullptr]);
6721 
6722  seat.wl_pointer = wl_seat_get_pointer(wl_seat);
6723 
6724  wl_pointer_add_listener(seat.wl_pointer
6725  , &Yetani::pointer_listener
6726  , &yetani->pointer
6727  );
6728  }
6729 
6730  if(capabilities & WL_SEAT_CAPABILITY_TOUCH)
6731  {
6732  ZAKERO_YETANI__DEBUG << "-- Got a touch device --\n";
6733  seat.wl_touch = wl_seat_get_touch(wl_seat);
6734 
6735  //wl_touch_add_listener(seat.wl_touch
6736  // , &Yetani::touch_listener
6737  // , data
6738  // );
6739  }
6740 }
6741 
6742 
6746 void Yetani::handlerSeatName(void* data
6747  , struct wl_seat* wl_seat
6748  , const char* name
6749  ) noexcept
6750 {
6751  ZAKERO_YETANI__DEBUG_VAR((uint64_t)wl_seat);
6752  ZAKERO_YETANI__DEBUG_VAR(name);
6753 
6754  Yetani* yetani = (Yetani*)data;
6755 
6756  yetani->seat_map[wl_seat].name = name;
6757 }
6758 
6759 // }}}
6760 // {{{ Wayland : Listener Handlers : SHM
6761 
6765 void Yetani::handlerShmFormat(void* data
6766  , struct wl_shm* /* Unused */
6767  , uint32_t value
6768  ) noexcept
6769 {
6770  Yetani* yetani = (Yetani*)data;
6771 
6772  wl_shm_format format = (wl_shm_format)value;
6773 
6774  if(vectorContains(yetani->shm_format_vector, format))
6775  {
6776  return;
6777  }
6778 
6779  yetani->shm_format_vector.push_back(format);
6780 }
6781 
6782 // }}}
6783 // {{{ Wayland : Listener Handlers : Surface
6784 
6788 void Yetani::handlerSurfaceEnter(void* data
6789  , struct wl_surface* wl_surface
6790  , struct wl_output* wl_output
6791  ) noexcept
6792 {
6793  //ZAKERO_YETANI__DEBUG << "-------------------------------------------\n";
6794  //ZAKERO_YETANI__DEBUG_VAR(data);
6795  //ZAKERO_YETANI__DEBUG_VAR(wl_surface);
6796  //ZAKERO_YETANI__DEBUG_VAR(wl_output);
6797 
6798  Yetani* yetani = (Yetani*)data;
6799  Yetani::OutputData& output_data = yetani->output_data;
6800 
6801  output_data.mutex.lock();
6802  output_data.surface_output_map[wl_surface].push_back(wl_output);
6803  output_data.mutex.unlock();
6804 }
6805 
6806 
6810 void Yetani::handlerSurfaceLeave(void* data
6811  , struct wl_surface* wl_surface
6812  , struct wl_output* wl_output
6813  ) noexcept
6814 {
6815  //ZAKERO_YETANI__DEBUG << "-------------------------------------------\n";
6816  //ZAKERO_YETANI__DEBUG_VAR(data);
6817  //ZAKERO_YETANI__DEBUG_VAR(wl_surface);
6818  //ZAKERO_YETANI__DEBUG_VAR(wl_output);
6819 
6820  Yetani* yetani = (Yetani*)data;
6821 
6822  Yetani::OutputData& output_data = yetani->output_data;
6823  std::lock_guard<std::mutex> lock(output_data.mutex);
6824 
6825  Yetani::VectorWlOutput& output_vector = output_data.surface_output_map[wl_surface];
6826 
6827  // Save the current wl_output device id
6828  struct wl_output* current_output = output_vector.front();
6829 
6830  // Remove the wl_output device id
6831  zakero::vectorErase(output_vector, wl_output);
6832 
6833  // Check if the current wl_output device id was removed
6834  if(current_output == output_vector.front())
6835  {
6836  // Current wl_output device was not removed
6837  // so nothing to do.
6838 
6839  return;
6840  }
6841 
6842  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
6843 
6844  if(surface_extent.preferred_unit == Yetani::SizeUnit::Pixel)
6845  {
6846  return;
6847  }
6848 
6849  // Convert the relative window size from the old wl_output device
6850  // to the new wl_output device.
6851 
6852  current_output = output_vector.front();
6853 
6854  Yetani::Output& output = output_data.output_map.at(current_output);
6855  Yetani::SizePixel new_size;
6856 
6857  if(surface_extent.preferred_unit == Yetani::SizeUnit::Millimeter)
6858  {
6859  auto p = yetani->convertMmToPixel(output
6860  , surface_extent.size_mm.width
6861  , surface_extent.size_mm.height
6862  );
6863 
6864  new_size = { p.first, p.second };
6865  }
6866  else // if(surface_extent.preferred_unit == Yetani::SizeUnit::Percent)
6867  {
6868  auto p = yetani->convertPercentToPixel(output
6869  , surface_extent.size_percent.width
6870  , surface_extent.size_percent.height
6871  );
6872 
6873  new_size = { p.first, p.second };
6874  }
6875 
6876  if(new_size.width <= 0)
6877  {
6878  new_size.width = 1;
6879  }
6880 
6881  if(new_size.height <= 0)
6882  {
6883  new_size.height = 1;
6884  }
6885 
6886  if((new_size.width != surface_extent.size_pixel.width)
6887  && (new_size.height != surface_extent.size_pixel.height)
6888  )
6889  {
6890  yetani->surface_resize_mutex_map[wl_surface].lock();
6891  {
6892  XdgSurface& surface = yetani->xdg_surface_map[wl_surface];
6893 
6894  surface_extent.size_pixel = new_size;
6895  surfaceCalculateSize(surface.yetani, surface.wl_surface, new_size);
6896  }
6897  yetani->surface_resize_mutex_map[wl_surface].unlock();
6898 
6899  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
6900  event.on_size_pixel_change(surface_extent.size_pixel);
6901  }
6902 }
6903 
6904 // }}}
6905 // {{{ Wayland : Listener Handlers : SwapBuffers
6906 
6910 void Yetani::handlerSwapBuffers(void* data
6911  , struct wl_callback* callback
6912  , uint32_t time_ms
6913  ) noexcept
6914 {
6915  Yetani::SurfaceFrame* surface_frame = (Yetani::SurfaceFrame*)data;
6916 
6917  wl_callback_destroy(callback);
6918 
6919  callback = wl_surface_frame(surface_frame->wl_surface);
6920 
6921  wl_callback_add_listener(callback
6922  , &frame_callback_listener
6923  , data
6924  );
6925 
6926  struct wl_buffer* wl_buffer = surface_frame->buffer_next.exchange(nullptr);
6927  if(wl_buffer != nullptr)
6928  {
6929  wl_buffer_add_listener(wl_buffer
6930  , &Yetani::buffer_listener
6931  , wl_buffer_get_user_data(wl_buffer)
6932  );
6933 
6934  surface_frame->time_ms = time_ms;
6935 
6936  wl_surface_attach(surface_frame->wl_surface, wl_buffer, 0, 0);
6937 
6938  wl_surface_damage(surface_frame->wl_surface
6939  , 0, 0
6940  , surface_frame->width, surface_frame->height
6941  );
6942  }
6943 
6944  wl_surface_commit(surface_frame->wl_surface);
6945 }
6946 
6947 // }}}
6948 // {{{ Wayland : Listener Handlers (Unstable)
6949 
6950 
6951 // }}}
6952 // {{{ XDG
6953 
6966 Yetani::WindowMode Yetani::toWindowMode(const Yetani::XdgState state
6967  ) noexcept
6968 {
6969  switch(state)
6970  {
6971  case Yetani::XdgState::Toplevel_Window_Fullscreen:
6972  return Yetani::WindowMode::Fullscreen;
6973 
6974  case Yetani::XdgState::Toplevel_Window_Maximized:
6975  return Yetani::WindowMode::Maximized;
6976 
6977  default:
6978  case Yetani::XdgState::Toplevel_Window_Normal:
6979  return Yetani::WindowMode::Normal;
6980  }
6981 }
6982 
6983 
6989 Yetani::XdgState Yetani::toXdgState(const Yetani::WindowMode window_mode
6990  ) noexcept
6991 {
6992  switch(window_mode)
6993  {
6994  case Yetani::WindowMode::Fullscreen:
6995  return Yetani::XdgState::Toplevel_Window_Fullscreen;
6996 
6997  case Yetani::WindowMode::Maximized:
6998  return Yetani::XdgState::Toplevel_Window_Maximized;
6999 
7000  default:
7001  case Yetani::WindowMode::Normal:
7002  return Yetani::XdgState::Toplevel_Window_Normal;
7003  }
7004 }
7005 
7006 // }}}
7007 // {{{ XDG : Surface
7008 
7029 struct xdg_surface* Yetani::xdgSurfaceCreate(struct wl_surface* wl_surface
7030  ) noexcept
7031 {
7032  XdgSurface& surface = xdg_surface_map[wl_surface];
7033 
7034  surface.yetani = this;
7035  surface.wl_surface = wl_surface;
7036 
7037  surface_extent_mutex.lock();
7038  {
7039  Yetani::SurfaceExtent& surface_extent = surface_extent_map[wl_surface];
7040 
7041  surface_extent.preferred_unit = Yetani::SizeUnit::Pixel;
7042  surface_extent.preferred_mm = { 160, 90 }; // 16:9 * 10mm
7043  surface_extent.preferred_percent = { 0.32, 0.18 }; // 16:9 * 0.02
7044  surface_extent.size_mm = { 160, 90 }; // 16:9 + 10mm
7045  surface_extent.size_percent = { 0.32, 0.18 }; // 16:9 * 0.02
7046  surface_extent.size_pixel = { 800, 450 }; // 16:9 * 50 pixels
7047  surface_extent.size_pixel_max = { 0, 0 }; // No maximum size
7048  surface_extent.size_pixel_min = { 0, 0 }; // No minimum size
7049  }
7050  surface_extent_mutex.unlock();
7051 
7052  output_notify_surface_vector.push_back(wl_surface);
7053 
7054  struct xdg_surface* xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base
7055  , wl_surface
7056  );
7057 
7058  xdg_state_change_mutex.lock();
7059  {
7060  xdg_state_change_map[xdg_surface] = {};
7061  }
7062  xdg_state_change_mutex.unlock();
7063 
7064  xdg_surface_add_listener(xdg_surface
7065  , &xdg_surface_listener
7066  , &surface
7067  );
7068 
7069  return xdg_surface;
7070 }
7071 
7072 
7081 void Yetani::xdgSurfaceDestroy(struct wl_surface* wl_surface
7082  , struct xdg_surface*& xdg_surface
7083  ) noexcept
7084 {
7085  if(xdg_surface)
7086  {
7087  xdg_surface_destroy(xdg_surface);
7088  }
7089 
7090  zakero::vectorErase(output_notify_surface_vector, wl_surface);
7091 
7092  if(xdg_surface_map.contains(wl_surface))
7093  {
7094  xdg_surface_map.erase(wl_surface);
7095  }
7096 
7097  xdg_state_change_mutex.lock();
7098  {
7099  if(xdg_state_change_map.contains(xdg_surface))
7100  {
7101  xdg_state_change_map.erase(xdg_surface);
7102  }
7103  }
7104  xdg_state_change_mutex.unlock();
7105 
7106  surface_extent_mutex.lock();
7107  {
7108  if(surface_extent_map.contains(wl_surface))
7109  {
7110  surface_extent_map.erase(wl_surface);
7111  }
7112  }
7113  surface_extent_mutex.unlock();
7114 
7115  xdg_surface = nullptr;
7116 }
7117 
7118 
7122 void Yetani::xdgSurfaceSetExtent(struct wl_surface* wl_surface
7123  , const Yetani::SizeUnit& size_unit
7124  , const Yetani::SizeMm& size_mm
7125  , const Yetani::SizePercent& size_percent
7126  , const Yetani::SizePixel& size_pixel
7127  ) noexcept
7128 {
7129  Yetani::SurfaceExtent& surface_extent = surface_extent_map[wl_surface];
7130 
7131  surface_extent.preferred_unit = size_unit;
7132  surface_extent.preferred_mm = size_mm;
7133  surface_extent.preferred_percent = size_percent;
7134  surface_extent.size_mm = size_mm;
7135  surface_extent.size_percent = size_percent;
7136  surface_extent.size_pixel = size_pixel;
7137  surface_extent.size_pixel_max = { 0, 0 };
7138  surface_extent.size_pixel_min = { 0, 0 };
7139 }
7140 
7141 // }}}
7142 // {{{ XDG : Toplevel
7143 
7182 struct xdg_toplevel* Yetani::xdgToplevelCreate(struct xdg_surface* xdg_surface
7183  ) noexcept
7184 {
7185  Yetani::XdgToplevel& toplevel = xdg_toplevel_map[xdg_surface];
7186 
7187  toplevel.close_request_lambda = Lambda_DoNothing;
7188  toplevel.state_change = &(xdg_state_change_map[xdg_surface]);
7189  toplevel.is_active = false;
7190  toplevel.window_state = Yetani::XdgState::Toplevel_Window_Normal;
7191  toplevel.is_active_lambda = LambdaBool_DoNothing;
7192  toplevel.window_state_lambda = LambdaWindowMode_DoNothing;
7193  toplevel.previous_size = { 0, 0 };
7194  toplevel.xdg_toplevel = nullptr;
7195 
7201  toplevel.state_change->push_back(Yetani::XdgState::Toplevel_Attach_Buffer);
7202 
7203  struct xdg_toplevel* xdg_toplevel = nullptr;
7204 
7205  xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
7206  toplevel.xdg_toplevel = xdg_toplevel;
7207 
7208  xdg_toplevel_add_listener(xdg_toplevel
7209  , &xdg_toplevel_listener
7210  , &toplevel
7211  );
7212 
7213  return xdg_toplevel;
7214 }
7215 
7216 
7223 void Yetani::xdgToplevelDestroy(struct xdg_surface* xdg_surface
7224  , struct xdg_toplevel*& xdg_toplevel
7225  ) noexcept
7226 {
7227  if(xdg_toplevel != nullptr)
7228  {
7229  xdg_toplevel_destroy(xdg_toplevel);
7230  }
7231 
7232  if(xdg_toplevel_map.contains(xdg_surface))
7233  {
7234  XdgToplevel& toplevel = xdg_toplevel_map[xdg_surface];
7235 
7236  toplevel.close_request_lambda = nullptr;
7237  toplevel.state_change = nullptr;
7238  toplevel.window_state = Yetani::XdgState::Unknown;
7239  toplevel.is_active = false;
7240  toplevel.is_active_lambda = nullptr;
7241  toplevel.window_state_lambda = nullptr;
7242 
7243  xdg_toplevel_map.erase(xdg_surface);
7244  }
7245 
7246  xdg_toplevel = nullptr;
7247 }
7248 
7249 
7259 void Yetani::xdgToplevelSizeChange(Yetani* yetani
7260  , struct wl_surface* wl_surface
7261  , const Yetani::SizePixel& size_pixel
7262  ) noexcept
7263 {
7264  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7265  Yetani::SizePixel new_size = surface_extent.size_pixel;
7266 
7267  if(((surface_extent.size_pixel_min.width == 0) || (size_pixel.width >= surface_extent.size_pixel_min.width))
7268  && ((surface_extent.size_pixel_max.width == 0) || (size_pixel.width <= surface_extent.size_pixel_max.width))
7269  )
7270  {
7271  new_size.width = size_pixel.width;
7272  }
7273 
7274  if(((surface_extent.size_pixel_min.height == 0) || (size_pixel.height >= surface_extent.size_pixel_min.height))
7275  && ((surface_extent.size_pixel_max.height == 0) || (size_pixel.height <= surface_extent.size_pixel_max.height))
7276  )
7277  {
7278  new_size.height = size_pixel.height;
7279  }
7280 
7281  if((new_size.width == surface_extent.size_pixel.width)
7282  && (new_size.height == surface_extent.size_pixel.height)
7283  )
7284  {
7285  return;
7286  }
7287 
7288  // Calculate Sizes
7289  Yetani::SizeMm size_mm;
7290  Yetani::SizePercent size_percent;
7291  yetani->convertPixel(wl_surface
7292  , size_pixel.width , size_pixel.height
7293  , size_mm.width , size_mm.height
7294  , size_percent.width, size_percent.height
7295  );
7296 
7297  yetani->surface_resize_mutex_map[wl_surface].lock();
7298  {
7299  surface_extent.size_pixel = new_size;
7300  surfaceCalculateSize(yetani, wl_surface, new_size);
7301  }
7302  yetani->surface_resize_mutex_map[wl_surface].unlock();
7303 
7304  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
7305  event.on_size_pixel_change(surface_extent.size_pixel);
7306  event.on_size_mm_change(surface_extent.size_mm);
7307  event.on_size_percent_change(surface_extent.size_percent);
7308 }
7309 
7310 
7314 void Yetani::xdgToplevelSizeMinMaxChange(Yetani* yetani
7315  , struct xdg_toplevel* xdg_toplevel
7316  , struct wl_surface* wl_surface
7317  , const Yetani::SizePixel& size_pixel_min
7318  , const Yetani::SizePixel& size_pixel_max
7319  ) noexcept
7320 {
7321  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7322 
7323  Yetani::SizePixel size_pixel = surface_extent.size_pixel;
7324  bool need_to_resize = false;
7325 
7326  if(size_pixel_max.width > 0
7327  && size_pixel_max.width < surface_extent.size_pixel.width
7328  )
7329  {
7330  need_to_resize = true;
7331  size_pixel.width = size_pixel_max.width;
7332  }
7333 
7334  if(size_pixel_max.height > 0
7335  && size_pixel_max.height < surface_extent.size_pixel.height
7336  )
7337  {
7338  need_to_resize = true;
7339  size_pixel.height = size_pixel_max.height;
7340  }
7341 
7342  if(size_pixel_min.width > 0
7343  && size_pixel_min.width > surface_extent.size_pixel.width
7344  )
7345  {
7346  need_to_resize = true;
7347  size_pixel.width = size_pixel_min.width;
7348  }
7349 
7350  if(size_pixel_min.height > 0
7351  && size_pixel_min.height > surface_extent.size_pixel.height
7352  )
7353  {
7354  need_to_resize = true;
7355  size_pixel.height = size_pixel_min.height;
7356  }
7357 
7358  if(need_to_resize)
7359  {
7360  xdg_toplevel_set_max_size(xdg_toplevel, 0, 0);
7361  xdg_toplevel_set_min_size(xdg_toplevel, 0, 0);
7362 
7363  yetani->surface_resize_mutex_map[wl_surface].lock();
7364  {
7365  surface_extent.size_pixel = size_pixel;
7366  surfaceCalculateSize(yetani, wl_surface, size_pixel);
7367  }
7368  yetani->surface_resize_mutex_map[wl_surface].unlock();
7369  }
7370 
7371  xdg_toplevel_set_min_size(xdg_toplevel
7372  , size_pixel_min.width
7373  , size_pixel_min.height
7374  );
7375 
7376  xdg_toplevel_set_max_size(xdg_toplevel
7377  , size_pixel_max.width
7378  , size_pixel_max.height
7379  );
7380 
7381  surface_extent.size_pixel_min = size_pixel_min;
7382  surface_extent.size_pixel_max = size_pixel_max;
7383 }
7384 
7385 
7389 void Yetani::xdgToplevelWindowChange(Yetani* yetani
7390  , struct wl_surface* wl_surface
7391  , Yetani::XdgToplevel& toplevel
7392  , const Yetani::XdgState window_state
7393  , const Yetani::SizePixel& size_pixel
7394  ) noexcept
7395 {
7396  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7397  Yetani::SizePixel new_size{1, 1};
7398 
7399  toplevel.window_state = window_state;
7400 
7401  if((toplevel.window_state == Yetani::XdgState::Toplevel_Window_Fullscreen)
7402  || (toplevel.window_state == Yetani::XdgState::Toplevel_Window_Maximized)
7403  )
7404  {
7405  if(toplevel.previous_size.width == 0)
7406  {
7407  xdg_toplevel_set_max_size(toplevel.xdg_toplevel, 0, 0);
7408  xdg_toplevel_set_min_size(toplevel.xdg_toplevel, 0, 0);
7409 
7410  toplevel.previous_size = surface_extent.size_pixel;
7411  }
7412 
7413  if((size_pixel.width != 0)
7414  && (size_pixel.height != 0)
7415  )
7416  {
7417  new_size = size_pixel;
7418  }
7419  }
7420  else if(toplevel.window_state == Yetani::XdgState::Toplevel_Window_Normal)
7421  {
7422  xdg_toplevel_set_max_size(toplevel.xdg_toplevel
7423  , surface_extent.size_pixel_max.width
7424  , surface_extent.size_pixel_max.height
7425  );
7426 
7427  xdg_toplevel_set_min_size(toplevel.xdg_toplevel
7428  , surface_extent.size_pixel_min.width
7429  , surface_extent.size_pixel_min.height
7430  );
7431 
7432  new_size = toplevel.previous_size;
7433  toplevel.previous_size.width = 0;
7434  }
7435 
7436  if(new_size == surface_extent.size_pixel)
7437  {
7438  return;
7439  }
7440 
7441  // Calculate Size
7442  Yetani::SizeMm size_mm;
7443  Yetani::SizePercent size_percent;
7444  yetani->convertPixel(wl_surface
7445  , size_pixel.width , size_pixel.height
7446  , size_mm.width , size_mm.height
7447  , size_percent.width, size_percent.height
7448  );
7449 
7450  yetani->surface_resize_mutex_map[wl_surface].lock();
7451  {
7452  surface_extent.size_mm = size_mm;
7453  surface_extent.size_percent = size_percent;
7454  surface_extent.size_pixel = new_size;
7455  surfaceCalculateSize(yetani, wl_surface, new_size);
7456  }
7457  yetani->surface_resize_mutex_map[wl_surface].unlock();
7458 
7459  toplevel.window_state_lambda(Yetani::toWindowMode(toplevel.window_state));
7460 
7461  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
7462  event.on_size_pixel_change(surface_extent.size_pixel);
7463  event.on_size_mm_change(surface_extent.size_mm);
7464  event.on_size_percent_change(surface_extent.size_percent);
7465 }
7466 
7467 // }}}
7468 // {{{ XDG : Decoration (Unstable)
7469 
7493 struct zxdg_toplevel_decoration_v1* Yetani::xdgDecorationCreate(struct xdg_surface* xdg_surface
7494  , struct xdg_toplevel* xdg_toplevel
7495  ) noexcept
7496 {
7497  if(decoration_manager == nullptr)
7498  {
7499  return nullptr;
7500  }
7501 
7502  /* *** From the xdg-decoration-unstable-v1 documentation ***
7503  *
7504  * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
7505  * buffer attached or committed is a client error.
7506  */
7507 
7508  zxdg_toplevel_decoration_v1* xdg_decoration =
7509  zxdg_decoration_manager_v1_get_toplevel_decoration(decoration_manager
7510  , xdg_toplevel
7511  );
7512 
7513  Yetani::XdgDecoration& decoration = xdg_decoration_map[xdg_surface];
7514  decoration.state_change = &(xdg_state_change_map[xdg_surface]);
7515  decoration.lambda = LambdaWindowDecorations_DoNothing;
7516  decoration.state = 0;
7517  decoration.is_present = false;
7518 
7519  zxdg_toplevel_decoration_v1_add_listener(xdg_decoration
7520  , &xdg_toplevel_decoration_listener
7521  , &decoration
7522  );
7523 
7524  return xdg_decoration;
7525 }
7526 
7527 
7533 void Yetani::xdgDecorationDestroy(struct xdg_surface* xdg_surface
7534  , struct xdg_toplevel* //xdg_toplevel ///< The XDG Toplevel
7535  , struct zxdg_toplevel_decoration_v1*& xdg_decoration
7536  ) noexcept
7537 {
7538  zxdg_toplevel_decoration_v1_destroy(xdg_decoration);
7539 
7540  if(xdg_decoration_map.contains(xdg_surface))
7541  {
7542  Yetani::XdgDecoration& decoration = xdg_decoration_map[xdg_surface];
7543  decoration.state_change = nullptr;
7544  decoration.lambda = nullptr;
7545  decoration.state = 0;
7546  decoration.is_present = false;
7547 
7548  xdg_decoration_map.erase(xdg_surface);
7549  }
7550 
7551  xdg_decoration = nullptr;
7552 }
7553 
7554 
7560 void Yetani::xdgDecorationChange(Yetani::XdgDecoration& decoration
7561  , const uint32_t decoration_state
7562  ) noexcept
7563 {
7564  if(decoration_state == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)
7565  {
7566  if(decoration.state != decoration_state)
7567  {
7568  decoration.state = decoration_state;
7569  decoration.is_present = false;
7570 
7571  decoration.lambda(
7572  Yetani::WindowDecorations::Client_Side
7573  );
7574  }
7575  }
7576  else if(decoration_state == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
7577  {
7578  if(decoration.state != decoration_state)
7579  {
7580  decoration.state = decoration_state;
7581  decoration.is_present = true;
7582  }
7583  else
7584  {
7585  decoration.is_present = !decoration.is_present;
7586  }
7587 
7588  if(decoration.is_present == true)
7589  {
7590  decoration.lambda(
7591  Yetani::WindowDecorations::Server_Side
7592  );
7593  }
7594  else
7595  {
7596  decoration.lambda(
7597  Yetani::WindowDecorations::Client_Side
7598  );
7599  }
7600  }
7601 }
7602 
7603 // }}}
7604 // {{{ XDG : Listener Handlers : Surface
7605 
7619 void Yetani::handlerXdgSurfaceConfigure(void* data
7620  , xdg_surface* xdg_surface
7621  , uint32_t serial
7622  ) noexcept
7623 {
7624  Yetani::XdgSurface& surface = *((Yetani::XdgSurface*)data);
7625  Yetani* yetani = surface.yetani;
7626 
7627  xdg_surface_ack_configure(xdg_surface, serial);
7628 
7629  VectorXdgStateChange& state_change = yetani->xdg_state_change_map[xdg_surface];
7630 
7631  if(state_change.empty())
7632  {
7633  return;
7634  }
7635 
7636  auto iter = std::begin(state_change);
7637  auto iter_end = std::end(state_change);
7638 
7639  while(iter != iter_end)
7640  {
7641  switch(*iter)
7642  {
7643  case Yetani::XdgState::Toplevel_Active:
7644  {
7645  Yetani::XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
7646 
7647  iter++;
7648  bool is_active = bool(*iter);
7649  if(toplevel.is_active != is_active)
7650  {
7651  toplevel.is_active = is_active;
7652 
7653  toplevel.is_active_lambda(is_active);
7654  }
7655  } break;
7656 
7657  case Yetani::XdgState::Toplevel_Attach_Buffer:
7658  {
7659  struct wl_surface* wl_surface = surface.wl_surface;
7660 
7661  SurfaceFrame& surface_frame =
7662  yetani->surface_frame_map[wl_surface];
7663 
7664  wl_surface_attach(surface_frame.wl_surface
7665  , surface_frame.buffer_next
7666  , 0, 0
7667  );
7668 
7669  struct wl_callback* callback = wl_surface_frame(surface_frame.wl_surface);
7670 
7671  wl_callback_add_listener(callback
7672  , &frame_callback_listener
7673  , &surface_frame
7674  );
7675 
7676  wl_surface_commit(surface_frame.wl_surface);
7677  } break;
7678 
7679  case Yetani::XdgState::Toplevel_Window_Normal:
7680  case Yetani::XdgState::Toplevel_Window_Maximized:
7681  case Yetani::XdgState::Toplevel_Window_Fullscreen:
7682  {
7683  struct wl_surface* wl_surface = surface.wl_surface;
7684 
7685  Yetani::XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
7686 
7687  Yetani::XdgState window_state = XdgState(*iter);
7688 
7689  Yetani::SizePixel size_pixel;
7690 
7691  iter++;
7692  size_pixel.width = *iter;
7693 
7694  iter++;
7695  size_pixel.height = *iter;
7696 
7697  if(toplevel.window_state != window_state)
7698  {
7699  xdgToplevelWindowChange(yetani
7700  , wl_surface
7701  , toplevel
7702  , window_state
7703  , size_pixel
7704  );
7705  }
7706  } break;
7707 
7708  case Yetani::XdgState::Toplevel_Resizing:
7709  {
7710  struct wl_surface* wl_surface = surface.wl_surface;
7711 
7712  Yetani::SizePixel size_pixel;
7713 
7714  iter++;
7715  size_pixel.width = *iter;
7716 
7717  iter++;
7718  size_pixel.height = *iter;
7719 
7720  if(size_pixel.width > 0
7721  && size_pixel.height > 0
7722  )
7723  {
7724  xdgToplevelSizeChange(yetani
7725  , wl_surface
7726  , size_pixel
7727  );
7728  }
7729  } break;
7730 
7731  case Yetani::XdgState::Toplevel_Decoration:
7732  {
7733  iter++;
7734  uint32_t decoration_state = *iter;
7735 
7736  Yetani::XdgDecoration& decoration = yetani->xdg_decoration_map[xdg_surface];
7737 
7738  xdgDecorationChange(decoration, decoration_state);
7739  } break;
7740  }
7741 
7742  iter++;
7743  }
7744 
7745  state_change.clear();
7746 }
7747 
7748 // }}}
7749 // {{{ XDG : Listener Handlers : Toplevel
7750 
7754 void Yetani::handlerXdgToplevelClose(void* data
7755  , struct xdg_toplevel* //xdg_toplevel ///< The toplevel surface
7756  ) noexcept
7757 {
7758  Yetani::XdgToplevel* toplevel = (Yetani::XdgToplevel*)data;
7759 
7760  toplevel->close_request_lambda();
7761 }
7762 
7763 
7767 void Yetani::handlerXdgToplevelConfigure(void* data
7768  , struct xdg_toplevel* //xdg_toplevel ///< The toplevel surface
7769  , int32_t width
7770  , int32_t height
7771  , struct wl_array* state_array
7772  ) noexcept
7773 {
7774  Yetani::XdgToplevel* toplevel = (Yetani::XdgToplevel*)data;
7775 
7776  Yetani::XdgState window_state = Yetani::XdgState::Toplevel_Window_Normal;
7777  int32_t is_active = 0;
7778 
7779  ZAKERO_YETANI__ARRAY_FOR_EACH(xdg_toplevel_state*, state_iter, state_array)
7780  {
7781  xdg_toplevel_state state = *state_iter;
7782 
7783  switch(state)
7784  {
7785  case XDG_TOPLEVEL_STATE_MAXIMIZED:
7786  window_state = Yetani::XdgState::Toplevel_Window_Maximized;
7787  break;
7788  case XDG_TOPLEVEL_STATE_FULLSCREEN:
7789  window_state = Yetani::XdgState::Toplevel_Window_Fullscreen;
7790  break;
7791  case XDG_TOPLEVEL_STATE_RESIZING:
7792  toplevel->state_change->push_back(Yetani::XdgState::Toplevel_Resizing);
7793  toplevel->state_change->push_back(width);
7794  toplevel->state_change->push_back(height);
7795  break;
7796  case XDG_TOPLEVEL_STATE_ACTIVATED:
7797  is_active = 1;
7798  break;
7799  case XDG_TOPLEVEL_STATE_TILED_LEFT:
7800  break;
7801  case XDG_TOPLEVEL_STATE_TILED_RIGHT:
7802  break;
7803  case XDG_TOPLEVEL_STATE_TILED_TOP:
7804  break;
7805  case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
7806  break;
7807  default:
7808  break;
7809  }
7810  }
7811 
7812  toplevel->state_change->push_back(window_state);
7813  toplevel->state_change->push_back(width);
7814  toplevel->state_change->push_back(height);
7815 
7816  toplevel->state_change->push_back(Yetani::XdgState::Toplevel_Active);
7817  toplevel->state_change->push_back(is_active);
7818 }
7819 
7820 // }}}
7821 // {{{ XDG : Listener Handlers : WM Base
7822 
7826 void Yetani::handlerXdgWmBasePing(void* //data ///< User data
7827  , struct xdg_wm_base* xdg_wm_base
7828  , uint32_t serial
7829  ) noexcept
7830 {
7831  xdg_wm_base_pong(xdg_wm_base, serial);
7832 }
7833 
7834 // }}}
7835 // {{{ XDG : Listener Handlers (Unstable) : Decoration
7836 
7840 void Yetani::handlerXdgToplevelDecorationConfigure(void* data
7841  , struct zxdg_toplevel_decoration_v1* //decoration ///< The Decoration object
7842  , uint32_t mode
7843  ) noexcept
7844 {
7845  Yetani::XdgDecoration* deco = (Yetani::XdgDecoration*)data;
7846 
7847  deco->state_change->push_back(Yetani::XdgState::Toplevel_Decoration);
7848  deco->state_change->push_back(mode);
7849 }
7850 
7851 // }}}
7852 // {{{ Window
7853 
7865 /* Disabled because Doxygen does not support "enum classes"
7866  *
7867  * \var Yetani::Client_Side
7868  * \brief The user app must draw the decorations.
7869  *
7870  * \var Yetani::Server_Side
7871  * \brief The Wayland Compositor will draw the decorations.
7872  */
7873 
7879 /* Disabled because Doxygen does not support "enum classes"
7880  *
7881  * \var Yetani::Normal
7882  * \brief A normal window.
7883  *
7884  * \var Yetani::Fullscreen
7885  * \brief A window that uses the entire screen, no borders.
7886  *
7887  * \var Yetani::Maximized
7888  * \brief A window that uses as much of the screen as possible.
7889  */
7890 
7891 
8019  , std::error_code& error
8020  ) noexcept
8021 {
8022  return windowCreate(Yetani::SizeUnit::Millimeter
8023  , size
8024  , { 0, 0 }
8025  , { 0, 0 }
8026  , SHM_FORMAT_DEFAULT
8027  , error
8028  );
8029 }
8030 
8031 
8045  , const wl_shm_format format
8046  ) noexcept
8047 {
8048  std::error_code error;
8049 
8050  return windowCreate(Yetani::SizeUnit::Millimeter
8051  , size
8052  , { 0, 0 }
8053  , { 0, 0 }
8054  , format
8055  , error
8056  );
8057 }
8058 
8059 
8076  , const wl_shm_format format
8077  , std::error_code& error
8078  ) noexcept
8079 {
8080  return windowCreate(Yetani::SizeUnit::Millimeter
8081  , size
8082  , { 0, 0 }
8083  , { 0, 0 }
8084  , format
8085  , error
8086  );
8087 }
8088 
8089 
8104  , std::error_code& error
8105  ) noexcept
8106 {
8107  return windowCreate(Yetani::SizeUnit::Percent
8108  , { 0, 0 }
8109  , size
8110  , { 0, 0 }
8111  , SHM_FORMAT_DEFAULT
8112  , error
8113  );
8114 }
8115 
8116 
8130  , const wl_shm_format format
8131  ) noexcept
8132 {
8133  std::error_code error;
8134 
8135  return windowCreate(Yetani::SizeUnit::Percent
8136  , { 0, 0 }
8137  , size
8138  , { 0, 0 }
8139  , format
8140  , error
8141  );
8142 }
8143 
8144 
8161  , const wl_shm_format format
8162  , std::error_code& error
8163  ) noexcept
8164 {
8165  return windowCreate(Yetani::SizeUnit::Percent
8166  , { 0, 0 }
8167  , size
8168  , { 0, 0 }
8169  , format
8170  , error
8171  );
8172 }
8173 
8174 
8189  , std::error_code& error
8190  ) noexcept
8191 {
8192  return windowCreate(Yetani::SizeUnit::Pixel
8193  , { 0, 0 }
8194  , { 0, 0 }
8195  , size
8196  , SHM_FORMAT_DEFAULT
8197  , error
8198  );
8199 }
8200 
8201 
8215  , const wl_shm_format format
8216  ) noexcept
8217 {
8218  std::error_code error;
8219 
8220  return windowCreate(Yetani::SizeUnit::Pixel
8221  , { 0, 0 }
8222  , { 0, 0 }
8223  , size
8224  , format
8225  , error
8226  );
8227 }
8228 
8229 
8246  , const wl_shm_format format
8247  , std::error_code& error
8248  ) noexcept
8249 {
8250  return windowCreate(Yetani::SizeUnit::Pixel
8251  , { 0, 0 }
8252  , { 0, 0 }
8253  , size
8254  , format
8255  , error
8256  );
8257 }
8258 
8259 
8267 Yetani::Window* Yetani::windowCreate(const Yetani::SizeUnit size_unit
8268  , const Yetani::SizeMm& size_mm
8269  , const Yetani::SizePercent& size_percent
8270  , const Yetani::SizePixel& size_pixel
8271  , const wl_shm_format pixel_format
8272  , std::error_code& error
8273  ) noexcept
8274 {
8275  if((size_unit == Yetani::SizeUnit::Millimeter)
8276  && (size_mm.width <= 0 || size_mm.height <= 0)
8277  )
8278  {
8279  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8280 
8281  return nullptr;
8282  }
8283 
8284  if((size_unit == Yetani::SizeUnit::Percent)
8285  && (size_percent.width <= 0 || size_percent.height <= 0)
8286  )
8287  {
8288  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8289 
8290  return nullptr;
8291  }
8292 
8293  if((size_unit == Yetani::SizeUnit::Pixel)
8294  && (size_pixel.width <= 0 || size_pixel.height <= 0)
8295  )
8296  {
8297  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8298 
8299  return nullptr;
8300  }
8301 
8302  const std::string file_name = "Zakero.Yetani."
8303  + std::to_string(ZAKERO_STEADY_TIME_NOW(nanoseconds))
8304  ;
8305 
8306  struct WindowData window_data =
8307  { .yetani = this
8308  , .wl_shm = shm
8309  , .wl_output = nullptr
8310  , .file_name = file_name
8311  , .size_mm = size_mm
8312  , .size_percent = size_percent
8313  , .size_pixel = size_pixel
8314  , .size_unit = size_unit
8315  , .pixel_format = pixel_format
8316  , .error = ZAKERO_YETANI__ERROR(Error_None)
8317  };
8318 
8319  windowDataInit(window_data);
8320 
8321  if(window_data.error)
8322  {
8323  error = window_data.error;
8324 
8325  return nullptr;
8326  }
8327 
8328  Yetani::Window* window = new Window(&window_data);
8329 
8330  if(window_data.error)
8331  {
8332  delete window;
8333  window = nullptr;
8334 
8335  ZAKERO_YETANI__DEBUG << to_string(window_data.error) << "\n";
8336 
8337  error = ZAKERO_YETANI__ERROR(Error_Window_Initialization_Failed);
8338 
8339  return nullptr;
8340  }
8341 
8342  error = ZAKERO_YETANI__ERROR(Error_None);
8343 
8344  return window;
8345 }
8346 
8347 
8351 void Yetani::windowDataInit(Yetani::WindowData& window_data
8352  ) noexcept
8353 {
8354  windowDataInitOutput(window_data);
8355 
8356  if(window_data.error)
8357  {
8358  return;
8359  }
8360 
8361  window_data.size_pixel.width = std::max(1, window_data.size_pixel.width);
8362  window_data.size_pixel.height = std::max(1, window_data.size_pixel.height);
8363 
8364  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8365 }
8366 
8367 
8371 void Yetani::windowDataInitOutput(Yetani::WindowData& window_data
8372  ) noexcept
8373 {
8374  std::lock_guard<std::mutex> lock(output_data.mutex);
8375 
8376  if(output_data.output_map.empty())
8377  {
8378  window_data.error = ZAKERO_YETANI__ERROR(Error_No_Output_Available);
8379 
8380  return;
8381  }
8382 
8383  const auto& iter = output_data.output_map.begin();
8384 
8385  window_data.wl_output = iter->first;
8386  Yetani::Output& output = iter->second;
8387 
8388  if(window_data.size_unit == Yetani::SizeUnit::Millimeter)
8389  {
8390  auto px = convertMmToPixel(output
8391  , window_data.size_mm.width
8392  , window_data.size_mm.height
8393  );
8394 
8395  auto pc = convertPixelToPercent(output
8396  , px.first
8397  , px.second
8398  );
8399 
8400  window_data.size_mm = window_data.size_mm;
8401  window_data.size_percent = { pc.first, pc.second };
8402  window_data.size_pixel = { px.first, px.second };
8403  }
8404  else if(window_data.size_unit == Yetani::SizeUnit::Percent)
8405  {
8406  auto px = convertPercentToPixel(output
8407  , window_data.size_percent.width
8408  , window_data.size_percent.height
8409  );
8410 
8411  auto mm = convertPixelToMm(output
8412  , px.first
8413  , px.second
8414  );
8415 
8416  window_data.size_mm = { mm.first, mm.second };
8417  window_data.size_percent = window_data.size_percent;
8418  window_data.size_pixel = { px.first, px.second };
8419  }
8420  else if(window_data.size_unit == Yetani::SizeUnit::Pixel)
8421  {
8422  auto mm = convertPixelToMm(output
8423  , window_data.size_pixel.width
8424  , window_data.size_pixel.height
8425  );
8426 
8427  auto pc = convertPixelToPercent(output
8428  , window_data.size_pixel.width
8429  , window_data.size_pixel.height
8430  );
8431 
8432  window_data.size_mm = { mm.first, mm.second };
8433  window_data.size_percent = { pc.first, pc.second };
8434  window_data.size_pixel = window_data.size_pixel;
8435  }
8436 
8437  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8438 }
8439 
8440 
8444 void Yetani::windowInitMemory(Yetani::WindowData& window_data
8445  , Yetani::Window::Memory& window_memory
8446  ) noexcept
8447 {
8448  size_t size_in_bytes = sizeInBytes(window_data.size_pixel
8449  , window_data.pixel_format
8450  ) * 3;
8451 
8452  window_data.error = window_memory.memory_pool.init(size_in_bytes
8453  , true
8454  , zakero::MemoryPool::Alignment::Bits_32
8455  );
8456 
8457  if(window_data.error)
8458  {
8459  return;
8460  }
8461 
8462  window_memory.wl_shm_pool = wl_shm_create_pool(window_data.wl_shm
8463  , window_memory.memory_pool.fd()
8464  , window_memory.memory_pool.size()
8465  );
8466 
8467  window_memory.memory_pool.sizeOnChange([&](size_t new_size)
8468  {
8469  wl_shm_pool_resize(window_memory.wl_shm_pool, new_size);
8470  });
8471 
8472  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8473 }
8474 
8475 
8479 void Yetani::windowInitOutput(Yetani::WindowData& window_data
8480  , struct wl_surface* wl_surface
8481  ) noexcept
8482 {
8483  std::lock_guard<std::mutex> lock(output_data.mutex);
8484 
8485  output_data.surface_output_map[wl_surface].push_back(window_data.wl_output);
8486 }
8487 
8488 
8492 void Yetani::windowEraseMemory(Yetani::Window::Memory& window_memory
8493  ) noexcept
8494 {
8495  if(window_memory.wl_shm_pool)
8496  {
8497  wl_shm_pool_destroy(window_memory.wl_shm_pool);
8498  window_memory.wl_shm_pool = nullptr;
8499  }
8500 }
8501 
8502 
8506 void Yetani::windowEraseOutput(struct wl_surface* wl_surface
8507  ) noexcept
8508 {
8509  std::lock_guard<std::mutex> lock(output_data.mutex);
8510 
8511  if(output_data.surface_output_map.contains(wl_surface))
8512  {
8513  output_data.surface_output_map.erase(wl_surface);
8514  }
8515 }
8516 
8517 
8521 void Yetani::windowEraseSurfaceExtent(struct wl_surface* wl_surface
8522  ) noexcept
8523 {
8524  std::lock_guard<std::mutex> lock(surface_extent_mutex);
8525 
8526  if(surface_extent_map.contains(wl_surface))
8527  {
8528  surface_extent_map.erase(wl_surface);
8529  }
8530 }
8531 
8532 
8536 void Yetani::windowAdd(Yetani::Window* window
8537  ) noexcept
8538 {
8539  std::lock_guard<std::mutex> lock(window_vector_mutex);
8540 
8541  window_vector.push_back(window);
8542 }
8543 
8544 
8548 void Yetani::windowRemove(Yetani::Window* window
8549  ) noexcept
8550 {
8551  std::lock_guard<std::mutex> lock(window_vector_mutex);
8552 
8553  zakero::vectorErase(window_vector, window);
8554 }
8555 
8556 // }}}
8557 // {{{ Window : Documentation
8558 
8724 // }}}
8725 // {{{ Window : Constructor / Destructor
8726 
8755  )
8756  : yetani {((Yetani::WindowData*)ptr)->yetani}
8757  , wl_buffer {nullptr}
8758  , wl_surface {nullptr}
8759  , xdg_surface {nullptr}
8760  , xdg_toplevel {nullptr}
8761  , xdg_decoration {nullptr}
8762  , window_memory {nullptr, ((Yetani::WindowData*)ptr)->file_name}
8763  , pixel_format {((Yetani::WindowData*)ptr)->pixel_format}
8764 {
8765  Yetani::WindowData& window_data = *((Yetani::WindowData*)ptr);
8766 
8767  yetani->windowInitMemory(window_data, window_memory);
8768  if(window_data.error)
8769  {
8770  return;
8771  }
8772 
8773  wl_surface = yetani->surfaceCreate(yetani
8774  , pixel_format
8775  , window_data.size_pixel
8776  , window_memory
8777  );
8778 
8779  xdg_surface = yetani->xdgSurfaceCreate(wl_surface);
8780 
8781  yetani->xdgSurfaceSetExtent(wl_surface
8782  , window_data.size_unit
8783  , window_data.size_mm
8784  , window_data.size_percent
8785  , window_data.size_pixel
8786  );
8787 
8788  xdg_toplevel = yetani->xdgToplevelCreate(xdg_surface);
8789 
8790  xdg_decoration = yetani->xdgDecorationCreate(xdg_surface, xdg_toplevel);
8791 
8792  wl_surface_commit(wl_surface);
8793 
8794  yetani->windowInitOutput(window_data, wl_surface);
8795  if(window_data.error)
8796  {
8797  return;
8798  }
8799 
8800  yetani->windowAdd(this);
8801 }
8802 
8803 
8808 {
8809  yetani->windowRemove(this);
8810 
8811  if(xdg_decoration != nullptr)
8812  {
8813  yetani->xdgDecorationDestroy(xdg_surface, xdg_toplevel, xdg_decoration);
8814  }
8815 
8816  if(xdg_toplevel != nullptr)
8817  {
8818  yetani->xdgToplevelDestroy(xdg_surface, xdg_toplevel);
8819  }
8820 
8821  if(xdg_surface != nullptr)
8822  {
8823  yetani->xdgSurfaceDestroy(wl_surface, xdg_surface);
8824  }
8825 
8826  if(wl_surface != nullptr)
8827  {
8828  yetani->windowEraseOutput(wl_surface);
8829  yetani->surfaceDestroy(yetani, wl_surface);
8830  yetani->windowEraseSurfaceExtent(wl_surface);
8831  }
8832 
8833  yetani->windowEraseMemory(window_memory);
8834 }
8835 
8836 // }}}
8837 // {{{ Window : Cursor
8838 
8852 std::error_code Yetani::Window::cursorUse(const std::string& name
8853  ) noexcept
8854 {
8855  if(name.empty())
8856  {
8857  return yetani->cursorDetach(wl_surface);
8858  }
8859 
8860  return yetani->cursorAttach(name, wl_surface);
8861 }
8862 
8863 
8870 {
8871  yetani->cursorHide(wl_surface);
8872 }
8873 
8874 
8881 {
8882  yetani->cursorShow(wl_surface);
8883 }
8884 
8885 // }}}
8886 // {{{ Window : Settings
8887 
8904 void Yetani::Window::classSet(const std::string& class_name
8905  ) noexcept
8906 {
8907  xdg_toplevel_set_app_id(xdg_toplevel, class_name.c_str());
8908 }
8909 
8910 
8917 void Yetani::Window::titleSet(const std::string& title
8918  ) noexcept
8919 {
8920  xdg_toplevel_set_title(xdg_toplevel, title.c_str());
8921 }
8922 
8923 
8944  ) noexcept
8945 {
8946  if(yetani->decoration_manager == nullptr)
8947  {
8948  return ZAKERO_YETANI__ERROR(Error_Server_Side_Decorations_Not_Available);
8949  }
8950 
8951  uint32_t decoration_state = decorations == Yetani::WindowDecorations::Server_Side
8952  ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
8953  : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE
8954  ;
8955 
8956  zxdg_toplevel_decoration_v1_set_mode(xdg_decoration
8957  , decoration_state
8958  );
8959 
8960  return ZAKERO_YETANI__ERROR(Error_None);
8961 }
8962 
8963 
8972 {
8973  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
8974 
8975  Yetani::WindowMode window_mode = Yetani::toWindowMode(toplevel.window_state);
8976 
8977  return window_mode;
8978 }
8979 
8980 
8990  ) noexcept
8991 {
8992  XdgState window_state = Yetani::toXdgState(window_mode);
8993 
8994  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
8995 
8996  if(toplevel.window_state == window_state)
8997  {
8998  return true;
8999  }
9000 
9001  return false;
9002 }
9003 
9004 
9014  ) noexcept
9015 {
9016  XdgState window_state = Yetani::toXdgState(window_mode);
9017 
9018  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9019 
9020  if(toplevel.window_state == window_state)
9021  {
9022  return;
9023  }
9024 
9025  switch(window_mode)
9026  {
9027  case WindowMode::Fullscreen:
9028  xdg_toplevel_set_fullscreen(xdg_toplevel, nullptr);
9029  break;
9030 
9031  case WindowMode::Maximized:
9032  xdg_toplevel_set_maximized(xdg_toplevel);
9033  break;
9034 
9035  case WindowMode::Normal:
9036  xdg_toplevel_unset_fullscreen(xdg_toplevel);
9037  xdg_toplevel_unset_maximized(xdg_toplevel);
9038  break;
9039  }
9040 }
9041 
9042 
9059 std::error_code Yetani::Window::sizeSet(const Yetani::SizeMm& size
9060  ) noexcept
9061 {
9062  if(size.width <= 0 || size.height <= 0)
9063  {
9064  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9065  }
9066 
9067  Yetani::SizePixel size_pixel = convertToPixel(size);
9068 
9069  if(size_pixel.width <= 0)
9070  {
9071  size_pixel.width = 1;
9072  }
9073 
9074  if(size_pixel.height <= 0)
9075  {
9076  size_pixel.height = 1;
9077  }
9078 
9079  yetani->surface_resize_mutex_map[wl_surface].lock();
9080  {
9081  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9082 
9083  surface_extent.preferred_unit = Yetani::SizeUnit::Millimeter;
9084  surface_extent.preferred_mm = size;
9085  surface_extent.size_pixel = size_pixel;
9086 
9087  surfaceCalculateSize(yetani, wl_surface, size_pixel);
9088  }
9089  yetani->surface_resize_mutex_map[wl_surface].unlock();
9090 
9091  return ZAKERO_YETANI__ERROR(Error_None);
9092 }
9093 
9094 
9111 std::error_code Yetani::Window::sizeSet(const Yetani::SizePercent& size
9112  ) noexcept
9113 {
9114  if(size.width <= 0 || size.height <= 0)
9115  {
9116  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9117  }
9118 
9119  Yetani::SizePixel size_pixel = convertToPixel(size);
9120 
9121  if(size_pixel.width <= 0)
9122  {
9123  size_pixel.width = 1;
9124  }
9125 
9126  if(size_pixel.height <= 0)
9127  {
9128  size_pixel.height = 1;
9129  }
9130 
9131  yetani->surface_resize_mutex_map[wl_surface].lock();
9132  {
9133  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9134 
9135  surface_extent.preferred_unit = Yetani::SizeUnit::Percent;
9136  surface_extent.preferred_percent = size;
9137  surface_extent.size_pixel = size_pixel;
9138 
9139  surfaceCalculateSize(yetani, wl_surface, size_pixel);
9140  }
9141  yetani->surface_resize_mutex_map[wl_surface].unlock();
9142 
9143  return ZAKERO_YETANI__ERROR(Error_None);
9144 }
9145 
9146 
9163 std::error_code Yetani::Window::sizeSet(const Yetani::SizePixel& size
9164  ) noexcept
9165 {
9166  if(size.width <= 0 || size.height <= 0)
9167  {
9168  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9169  }
9170 
9171  yetani->surface_resize_mutex_map[wl_surface].lock();
9172  {
9173  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9174 
9175  surface_extent.preferred_unit = Yetani::SizeUnit::Pixel;
9176  surface_extent.size_pixel = size;
9177 
9178  surfaceCalculateSize(yetani, wl_surface, size);
9179  }
9180  yetani->surface_resize_mutex_map[wl_surface].unlock();
9181 
9182  return ZAKERO_YETANI__ERROR(Error_None);
9183 }
9184 
9185 
9197 std::error_code Yetani::Window::sizeSetMinMax(const Yetani::SizeMm& size_min
9198  , const Yetani::SizeMm& size_max
9199  ) noexcept
9200 {
9201  std::error_code error = validateMinMax<Yetani::SizeMm>(size_min, size_max);
9202  if(error)
9203  {
9204  return error;
9205  }
9206 
9207  Yetani::SizePixel size_pixel_min;
9208  Yetani::SizePixel size_pixel_max;
9209 
9210  {
9211  Yetani::OutputData& output_data = yetani->output_data;
9212 
9213  std::lock_guard<std::mutex> lock(output_data.mutex);
9214 
9215  Yetani::VectorWlOutput& vector = output_data.surface_output_map[wl_surface];
9216  struct wl_output* wl_output = vector.front();
9217  const Yetani::Output& output = output_data.output_map[wl_output];
9218 
9219  auto min = yetani->convertMmToPixel(output, size_min.width, size_min.height);
9220  size_pixel_min = { min.first, min.second };
9221 
9222  auto max = yetani->convertMmToPixel(output, size_max.width, size_max.height);
9223  size_pixel_max = { max.first, max.second };
9224  }
9225 
9226  yetani->xdgToplevelSizeMinMaxChange(yetani
9227  , xdg_toplevel
9228  , wl_surface
9229  , size_pixel_min
9230  , size_pixel_max
9231  );
9232 
9233  return ZAKERO_YETANI__ERROR(Error_None);
9234 }
9235 
9236 
9248 std::error_code Yetani::Window::sizeSetMinMax(const Yetani::SizePercent& size_min
9249  , const Yetani::SizePercent& size_max
9250  ) noexcept
9251 {
9252  std::error_code error = validateMinMax<Yetani::SizePercent>(size_min, size_max);
9253  if(error)
9254  {
9255  return error;
9256  }
9257 
9258  Yetani::SizePixel size_pixel_min;
9259  Yetani::SizePixel size_pixel_max;
9260 
9261  {
9262  Yetani::OutputData& output_data = yetani->output_data;
9263 
9264  std::lock_guard<std::mutex> lock(output_data.mutex);
9265 
9266  Yetani::VectorWlOutput& vector = output_data.surface_output_map[wl_surface];
9267  struct wl_output* wl_output = vector.front();
9268  const Yetani::Output& output = output_data.output_map[wl_output];
9269 
9270  auto min = yetani->convertPercentToPixel(output, size_min.width, size_min.height);
9271  size_pixel_min = { min.first, min.second };
9272 
9273  auto max = yetani->convertPercentToPixel(output, size_max.width, size_max.height);
9274  size_pixel_max = { max.first, max.second };
9275  }
9276 
9277  yetani->xdgToplevelSizeMinMaxChange(yetani
9278  , xdg_toplevel
9279  , wl_surface
9280  , size_pixel_min
9281  , size_pixel_max
9282  );
9283 
9284  return ZAKERO_YETANI__ERROR(Error_None);
9285 }
9286 
9287 
9299 std::error_code Yetani::Window::sizeSetMinMax(const Yetani::SizePixel& size_min
9300  , const Yetani::SizePixel& size_max
9301  ) noexcept
9302 {
9303  std::error_code error = validateMinMax<Yetani::SizePixel>(size_min, size_max);
9304  if(error)
9305  {
9306  return error;
9307  }
9308 
9309  yetani->xdgToplevelSizeMinMaxChange(yetani
9310  , xdg_toplevel
9311  , wl_surface
9312  , size_min
9313  , size_max
9314  );
9315 
9316  return ZAKERO_YETANI__ERROR(Error_None);
9317 }
9318 
9319 // }}}
9320 // {{{ Window : Rendering
9321 
9358 std::error_code Yetani::Window::imageNext(uint8_t*& image
9359  , Yetani::SizePixel& size
9360  ) noexcept
9361 {
9362  if(wl_buffer != nullptr)
9363  {
9364  bufferDestroy(wl_buffer);
9365  }
9366 
9367  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
9368 
9369  yetani->surface_resize_mutex_map[wl_surface].lock();
9370  {
9371  wl_buffer = bufferCreate(surface_size
9372  , &window_memory
9373  , &yetani->buffer
9374  );
9375  }
9376  yetani->surface_resize_mutex_map[wl_surface].unlock();
9377 
9378  image = window_memory.memory_pool.addressOf(
9379  yetani->buffer.map[wl_buffer].offset
9380  );
9381 
9382  size = { surface_size.width, surface_size.height };
9383 
9384  return ZAKERO_YETANI__ERROR(Error_None);
9385 }
9386 
9387 
9395 {
9396  if(wl_buffer == nullptr)
9397  {
9398  // This nullptr check is needed because:
9399  // - If imagePresent() is called before imageNext() then
9400  // wl_buffer could be nullptr.
9401  // - There is a chance that a valid "buffer_next" can be
9402  // replaced with a nullptr, and this will cause a
9403  // frame-drop.
9404 
9405  return;
9406  }
9407 
9408  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
9409 
9410  wl_buffer = surface_frame.buffer_next.exchange(wl_buffer);
9411 }
9412 
9413 
9426 uint32_t Yetani::Window::time() const noexcept
9427 {
9428  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
9429 
9430  return surface_frame.time_ms;
9431 }
9432 
9433 // }}}
9434 // {{{ Window : Misc
9435 
9444 uint8_t Yetani::Window::bytesPerPixel() const noexcept
9445 {
9446  return yetani->shmFormatBytesPerPixel(pixel_format);
9447 }
9448 
9449 
9458 {
9459  xdg_toplevel_set_minimized(xdg_toplevel);
9460 }
9461 
9462 // }}}
9463 // {{{ Window : Measurement Conversion
9464 
9473  ) const noexcept
9474 {
9475  const Yetani::OutputData& output_data = yetani->output_data;
9476 
9477  std::lock_guard<std::mutex> lock(output_data.mutex);
9478 
9479  struct wl_output* wl_output = output_data.surface_output_map.at(wl_surface).front();
9480  const Yetani::Output& output = output_data.output_map.at(wl_output);
9481 
9482  auto p = yetani->convertPixelToMm(output, point.x, point.y);
9483 
9484  return { point.time, p.first, p.second };
9485 }
9486 
9487 
9496  ) const noexcept
9497 {
9498  const Yetani::OutputData& output_data = yetani->output_data;
9499 
9500  std::lock_guard<std::mutex> lock(output_data.mutex);
9501 
9502  struct wl_output* wl_output = output_data.surface_output_map.at(wl_surface).front();
9503  const Yetani::Output& output = output_data.output_map.at(wl_output);
9504 
9505  auto p = yetani->convertPixelToPercent(output, point.x, point.y);
9506 
9507  return { point.time, p.first, p.second };
9508 }
9509 
9510 
9519  ) const noexcept
9520 {
9521  Yetani::OutputData& output_data = yetani->output_data;
9522 
9523  std::lock_guard<std::mutex> lock(output_data.mutex);
9524 
9525  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9526  const Yetani::Output& output = output_data.output_map[wl_output];
9527 
9528  auto p = yetani->convertMmToPixel(output, point.x, point.y);
9529 
9530  return { point.time, p.first, p.second };
9531 }
9532 
9533 
9542  ) const noexcept
9543 {
9544  Yetani::OutputData& output_data = yetani->output_data;
9545 
9546  std::lock_guard<std::mutex> lock(output_data.mutex);
9547 
9548  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9549  const Yetani::Output& output = output_data.output_map[wl_output];
9550 
9551  auto p = yetani->convertPercentToPixel(output, point.x, point.y);
9552 
9553  return { point.time, p.first, p.second };
9554 }
9555 
9556 
9565  ) const noexcept
9566 {
9567  Yetani::OutputData& output_data = yetani->output_data;
9568 
9569  std::lock_guard<std::mutex> lock(output_data.mutex);
9570 
9571  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9572  const Yetani::Output& output = output_data.output_map[wl_output];
9573 
9574  auto p = yetani->convertPixelToMm(output, size.width, size.height);
9575 
9576  return { p.first, p.second };
9577 }
9578 
9579 
9588  ) const noexcept
9589 {
9590  Yetani::OutputData& output_data = yetani->output_data;
9591 
9592  std::lock_guard<std::mutex> lock(output_data.mutex);
9593 
9594  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9595  const Yetani::Output& output = output_data.output_map[wl_output];
9596 
9597  auto p = yetani->convertPixelToPercent(output, size.width, size.height);
9598 
9599  return { p.first, p.second };
9600 }
9601 
9602 
9611  ) const noexcept
9612 {
9613  Yetani::OutputData& output_data = yetani->output_data;
9614 
9615  std::lock_guard<std::mutex> lock(output_data.mutex);
9616 
9617  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9618  const Yetani::Output& output = output_data.output_map[wl_output];
9619 
9620  auto p = yetani->convertMmToPixel(output, size.width, size.height);
9621 
9622  return { p.first, p.second };
9623 }
9624 
9625 
9634  ) const noexcept
9635 {
9636  Yetani::OutputData& output_data = yetani->output_data;
9637 
9638  std::lock_guard<std::mutex> lock(output_data.mutex);
9639 
9640  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9641  const Yetani::Output& output = output_data.output_map[wl_output];
9642 
9643  auto p = yetani->convertPercentToPixel(output, size.width, size.height);
9644 
9645  return { p.first, p.second };
9646 }
9647 
9648 // }}}
9649 // {{{ Window : Event Handling
9650 
9663  ) noexcept
9664 {
9665  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9666 
9667  if(lambda == nullptr)
9668  {
9669  toplevel.close_request_lambda = Lambda_DoNothing;
9670  }
9671  else
9672  {
9673  toplevel.close_request_lambda = lambda;
9674  }
9675 }
9676 
9677 
9688  ) noexcept
9689 {
9690  XdgDecoration& decoration = yetani->xdg_decoration_map[xdg_surface];
9691 
9692  if(lambda == nullptr)
9693  {
9694  decoration.lambda = LambdaWindowDecorations_DoNothing;
9695  }
9696  else
9697  {
9698  decoration.lambda = lambda;
9699  }
9700 }
9701 
9702 
9717  ) noexcept
9718 {
9719  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9720 
9721  if(lambda == nullptr)
9722  {
9723  toplevel.is_active_lambda = LambdaBool_DoNothing;
9724  }
9725  else
9726  {
9727  toplevel.is_active_lambda = lambda;
9728  }
9729 }
9730 
9731 
9738  ) noexcept
9739 {
9740  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9741  {
9742  return;
9743  }
9744 
9745  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9746 
9747  if(lambda == nullptr)
9748  {
9749  event.on_enter = Lambda_DoNothing;
9750  }
9751  else
9752  {
9753  event.on_enter = lambda;
9754  }
9755 }
9756 
9757 
9764  ) noexcept
9765 {
9766  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9767  {
9768  return;
9769  }
9770 
9771  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9772 
9773  if(lambda == nullptr)
9774  {
9775  event.on_leave = Lambda_DoNothing;
9776  }
9777  else
9778  {
9779  event.on_leave = lambda;
9780  }
9781 }
9782 
9783 
9792  ) noexcept
9793 {
9794  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9795  {
9796  return;
9797  }
9798 
9799  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9800 
9801  if(lambda == nullptr)
9802  {
9803  event.on_key = LambdaKey_DoNothing;
9804  }
9805  else
9806  {
9807  event.on_key = lambda;
9808  }
9809 }
9810 
9811 
9819  ) noexcept
9820 {
9821  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9822 
9823  if(lambda == nullptr)
9824  {
9825  toplevel.window_state_lambda = LambdaWindowMode_DoNothing;
9826  }
9827  else
9828  {
9829  toplevel.window_state_lambda = lambda;
9830  }
9831 }
9832 
9833 
9848  ) noexcept
9849 {
9850  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9851 
9852  if(lambda == nullptr)
9853  {
9854  event.on_size_mm_change = LambdaSizeMm_DoNothing;
9855  }
9856  else
9857  {
9858  event.on_size_mm_change = lambda;
9859  }
9860 }
9861 
9862 
9877  ) noexcept
9878 {
9879  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9880 
9881  if(lambda == nullptr)
9882  {
9883  event.on_size_percent_change = LambdaSizePercent_DoNothing;
9884  }
9885  else
9886  {
9887  event.on_size_percent_change = lambda;
9888  }
9889 }
9890 
9891 
9906  ) noexcept
9907 {
9908  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9909 
9910  if(lambda == nullptr)
9911  {
9912  event.on_size_pixel_change = LambdaSizePixel_DoNothing;
9913  }
9914  else
9915  {
9916  event.on_size_pixel_change = lambda;
9917  }
9918 }
9919 
9920 
9929  ) noexcept
9930 {
9931  if(yetani->pointer.event_map.contains(wl_surface) == false)
9932  {
9933  return;
9934  }
9935 
9936  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9937 
9938  if(lambda == nullptr)
9939  {
9940  event.on_button_mm = LambdaButtonMm_DoNothing;
9941  }
9942  else
9943  {
9944  event.on_button_mm = lambda;
9945  }
9946 }
9947 
9948 
9957  ) noexcept
9958 {
9959  if(yetani->pointer.event_map.contains(wl_surface) == false)
9960  {
9961  return;
9962  }
9963 
9964  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9965 
9966  if(lambda == nullptr)
9967  {
9968  event.on_button_percent = LambdaButtonPercent_DoNothing;
9969  }
9970  else
9971  {
9972  event.on_button_percent = lambda;
9973  }
9974 }
9975 
9976 
9985  ) noexcept
9986 {
9987  if(yetani->pointer.event_map.contains(wl_surface) == false)
9988  {
9989  return;
9990  }
9991 
9992  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9993 
9994  if(lambda == nullptr)
9995  {
9996  event.on_button_pixel = LambdaButtonPixel_DoNothing;
9997  }
9998  else
9999  {
10000  event.on_button_pixel = lambda;
10001  }
10002 }
10003 
10004 
10016  ) noexcept
10017 {
10018  if(yetani->pointer.event_map.contains(wl_surface) == false)
10019  {
10020  return;
10021  }
10022 
10023  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10024 
10025  if(lambda == nullptr)
10026  {
10027  event.on_enter_mm = LambdaPointMm_DoNothing;
10028  }
10029  else
10030  {
10031  event.on_enter_mm = lambda;
10032  }
10033 }
10034 
10035 
10047  ) noexcept
10048 {
10049  if(yetani->pointer.event_map.contains(wl_surface) == false)
10050  {
10051  return;
10052  }
10053 
10054  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10055 
10056  if(lambda == nullptr)
10057  {
10058  event.on_enter_percent = LambdaPointPercent_DoNothing;
10059  }
10060  else
10061  {
10062  event.on_enter_percent = lambda;
10063  }
10064 }
10065 
10066 
10078  ) noexcept
10079 {
10080  if(yetani->pointer.event_map.contains(wl_surface) == false)
10081  {
10082  return;
10083  }
10084 
10085  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10086 
10087  if(lambda == nullptr)
10088  {
10089  event.on_enter_pixel = LambdaPointPixel_DoNothing;
10090  }
10091  else
10092  {
10093  event.on_enter_pixel = lambda;
10094  }
10095 }
10096 
10097 
10106  ) noexcept
10107 {
10108  if(yetani->pointer.event_map.contains(wl_surface) == false)
10109  {
10110  return;
10111  }
10112 
10113  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10114 
10115  if(lambda == nullptr)
10116  {
10117  event.on_leave = Lambda_DoNothing;
10118  }
10119  else
10120  {
10121  event.on_leave = lambda;
10122  }
10123 }
10124 
10125 
10134  ) noexcept
10135 {
10136  if(yetani->pointer.event_map.contains(wl_surface) == false)
10137  {
10138  return;
10139  }
10140 
10141  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10142 
10143  if(lambda == nullptr)
10144  {
10145  event.on_motion_mm = LambdaPointMm_DoNothing;
10146  }
10147  else
10148  {
10149  event.on_motion_mm = lambda;
10150  }
10151 }
10152 
10153 
10162  ) noexcept
10163 {
10164  if(yetani->pointer.event_map.contains(wl_surface) == false)
10165  {
10166  return;
10167  }
10168 
10169  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10170 
10171  if(lambda == nullptr)
10172  {
10173  event.on_motion_percent = LambdaPointPercent_DoNothing;
10174  }
10175  else
10176  {
10177  event.on_motion_percent = lambda;
10178  }
10179 }
10180 
10181 
10190  ) noexcept
10191 {
10192  if(yetani->pointer.event_map.contains(wl_surface) == false)
10193  {
10194  return;
10195  }
10196 
10197  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10198 
10199  if(lambda == nullptr)
10200  {
10201  event.on_motion_pixel = LambdaPointPixel_DoNothing;
10202  }
10203  else
10204  {
10205  event.on_motion_pixel = lambda;
10206  }
10207 }
10208 
10209 
10217  ) noexcept
10218 {
10219  if(yetani->pointer.event_map.contains(wl_surface) == false)
10220  {
10221  return;
10222  }
10223 
10224  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10225 
10226  if(lambda == nullptr)
10227  {
10228  event.on_axis = LambdaAxis_DoNothing;
10229  }
10230  else
10231  {
10232  event.on_axis = lambda;
10233  }
10234 }
10235 
10236 
10244  ) noexcept
10245 {
10246  if(yetani->pointer.event_map.contains(wl_surface) == false)
10247  {
10248  return;
10249  }
10250 
10251  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10252 
10253  if(lambda == nullptr)
10254  {
10255  event.on_axis_source = Lambda_DoNothing;
10256  }
10257  else
10258  {
10259  event.on_axis_source = lambda;
10260  }
10261 }
10262 
10263 
10271  ) noexcept
10272 {
10273  if(yetani->pointer.event_map.contains(wl_surface) == false)
10274  {
10275  return;
10276  }
10277 
10278  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10279 
10280  if(lambda == nullptr)
10281  {
10282  event.on_axis_stop = Lambda_DoNothing;
10283  }
10284  else
10285  {
10286  event.on_axis_stop = lambda;
10287  }
10288 }
10289 
10290 
10298  ) noexcept
10299 {
10300  if(yetani->pointer.event_map.contains(wl_surface) == false)
10301  {
10302  return;
10303  }
10304 
10305  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10306 
10307  if(lambda == nullptr)
10308  {
10309  event.on_axis_discrete = Lambda_DoNothing;
10310  }
10311  else
10312  {
10313  event.on_axis_discrete = lambda;
10314  }
10315 }
10316 
10317 // }}}
10318 // {{{ Window : Helpers
10319 
10320 
10321 // }}}
10322 // {{{ Convenience
10323 
10331 std::string to_string(const wl_shm_format& shm_format
10332  ) noexcept
10333 {
10334  return Yetani::shmFormatName(shm_format);
10335 }
10336 
10337 
10345 std::string to_string(const Yetani::Key& key
10346  ) noexcept
10347 {
10348  return std::string()
10349  + "{ \"time\": " + std::to_string(key.time)
10350  + ", \"code\": " + std::to_string(key.code)
10351  + ", \"state\": \"" + zakero::to_string(key.state) + "\""
10352  + " }";
10353 }
10354 
10355 
10364 std::string to_string(const Yetani::KeyModifier& key_modifier
10365  ) noexcept
10366 {
10367  auto mod_to_str = [](std::string& s, uint32_t m)
10368  {
10369  s += "[";
10370  std::string delim = "";
10371 
10373  {
10374  s += delim + "\"Shift\"";
10375  delim = ",";
10376  }
10377 
10379  {
10380  s += delim + "\"CapsLock\"";
10381  delim = ",";
10382  }
10383 
10385  {
10386  s += delim + "\"Control\"";
10387  delim = ",";
10388  }
10389 
10390  if(m & Yetani::KeyModifier_Alt)
10391  {
10392  s += delim + "\"Alt\"";
10393  delim = ",";
10394  }
10395 
10396  if(m & Yetani::KeyModifier_NumLock)
10397  {
10398  s += delim + "\"NumLock\"";
10399  }
10400 
10401  if(m & Yetani::KeyModifier_Meta)
10402  {
10403  s += delim + "\"Meta\"";
10404  }
10405 
10406  s += "]";
10407  };
10408 
10409  std::string str = "{ \"pressed\": ";
10410  mod_to_str(str, key_modifier.pressed);
10411 
10412  str += ", \"latched\": ";
10413  mod_to_str(str, key_modifier.latched);
10414 
10415  str += ", \"locked\": ";
10416  mod_to_str(str, key_modifier.locked);
10417 
10418  str += " }";
10419 
10420  return str;
10421 }
10422 
10423 
10431 std::string to_string(const Yetani::KeyState& key_state
10432  ) noexcept
10433 {
10434  switch(key_state)
10435  {
10436  case Yetani::KeyState::Pressed: return "Pressed";
10437  case Yetani::KeyState::Released: return "Released";
10438  case Yetani::KeyState::Repeat: return "Repeat";
10439  default: return "";
10440  }
10441 }
10442 
10443 
10451 std::string to_string(const Yetani::Output& output
10452  ) noexcept
10453 {
10454  return std::string()
10455  + "{ \"x\": " + std::to_string(output.x)
10456  + ", \"y\": " + std::to_string(output.y)
10457  + ", \"physical_width_mm\": " + std::to_string(output.physical_width_mm)
10458  + ", \"physical_height_mm\": " + std::to_string(output.physical_height_mm)
10459  + ", \"subpixel\": " + std::to_string(output.subpixel)
10460  + ", \"subpixel_name\": \"" + Yetani::outputSubpixelName(output.subpixel) + "\""
10461  + ", \"make\": \"" + output.make + "\""
10462  + ", \"model\": \"" + output.model + "\""
10463  + ", \"transform\": " + std::to_string(output.transform)
10464  + ", \"transform_name\": \"" + Yetani::outputTransformName(output.transform) + "\""
10465  + ", \"flags\": " + std::to_string(output.flags)
10466  + ", \"width\": " + std::to_string(output.width)
10467  + ", \"height\": " + std::to_string(output.height)
10468  + ", \"refresh_mHz\": " + std::to_string(output.refresh_mHz)
10469  + ", \"scale_factor\": " + std::to_string(output.scale_factor)
10470  + ", \"pixels_per_mm_horizontal\": " + std::to_string(output.pixels_per_mm_horizontal)
10471  + ", \"pixels_per_mm_vertical\": " + std::to_string(output.pixels_per_mm_vertical)
10472  + " }";
10473 }
10474 
10475 
10483 std::string to_string(const Yetani::PointMm& point
10484  ) noexcept
10485 {
10486  return std::string()
10487  + "{ \"time\": " + std::to_string(point.time)
10488  + ", \"x\": " + std::to_string(point.x)
10489  + ", \"y\": " + std::to_string(point.y)
10490  + " }";
10491 }
10492 
10493 
10501 std::string to_string(const Yetani::PointPercent& point
10502  ) noexcept
10503 {
10504  return std::string()
10505  + "{ \"time\": " + std::to_string(point.time)
10506  + ", \"x\": " + std::to_string(point.x)
10507  + ", \"y\": " + std::to_string(point.y)
10508  + " }";
10509 }
10510 
10511 
10519 std::string to_string(const Yetani::PointPixel& point
10520  ) noexcept
10521 {
10522  return std::string()
10523  + "{ \"time\": " + std::to_string(point.time)
10524  + ", \"x\": " + std::to_string(point.x)
10525  + ", \"y\": " + std::to_string(point.y)
10526  + " }";
10527 }
10528 
10529 
10537 std::string to_string(const Yetani::PointerAxis& axis
10538  ) noexcept
10539 {
10540  return std::string()
10541  + "{ \"time\": " + std::to_string(axis.time)
10542  + ", \"steps\": " + std::to_string(axis.steps)
10543  + ", \"distance\": " + std::to_string(axis.distance)
10544  + ", \"source\": " + zakero::to_string(axis.source)
10545  + ", \"type\": " + zakero::to_string(axis.type)
10546  + " }";
10547 }
10548 
10549 
10557 std::string to_string(const Yetani::PointerAxisSource& source
10558  ) noexcept
10559 {
10560  switch(source)
10561  {
10562  case Yetani::PointerAxisSource::Continuous: return "Continuous";
10563  case Yetani::PointerAxisSource::Finger: return "Finger";
10564  case Yetani::PointerAxisSource::Wheel: return "Wheel";
10565  case Yetani::PointerAxisSource::Wheel_Tilt: return "Wheel Tilt";
10566  case Yetani::PointerAxisSource::Unknown: [[fallthrough]];
10567  default: return "";
10568  }
10569 }
10570 
10571 
10579 std::string to_string(const Yetani::PointerAxisType& type
10580  ) noexcept
10581 {
10582  switch(type)
10583  {
10584  case Yetani::PointerAxisType::Horizontal: return "Horizontal";
10585  case Yetani::PointerAxisType::Vertical: return "Vertical";
10586  case Yetani::PointerAxisType::Unknown: [[fallthrough]];
10587  default: return "";
10588  }
10589 }
10590 
10591 
10599 std::string to_string(const Yetani::PointerButton& button
10600  ) noexcept
10601 {
10602  return std::string()
10603  + "{ \"code\": " + std::to_string(button.code)
10604  + ", \"state\": " + zakero::to_string(button.state)
10605  + " }";
10606 }
10607 
10608 
10616 std::string to_string(const Yetani::PointerButtonState& button_state
10617  ) noexcept
10618 {
10619  switch(button_state)
10620  {
10621  case Yetani::PointerButtonState::Pressed: return "Pressed";
10622  case Yetani::PointerButtonState::Released: return "Released";
10623  default: return "";
10624  }
10625 }
10626 
10627 
10635 std::string to_string(const Yetani::SizeMm& size
10636  ) noexcept
10637 {
10638  return std::string()
10639  + "{ \"width\": " + std::to_string(size.width)
10640  + ", \"height\": " + std::to_string(size.height)
10641  + " }";
10642 }
10643 
10644 
10652 std::string to_string(const Yetani::SizePercent& size
10653  ) noexcept
10654 {
10655  return std::string()
10656  + "{ \"width\": " + std::to_string(size.width)
10657  + ", \"height\": " + std::to_string(size.height)
10658  + " }";
10659 }
10660 
10661 
10669 std::string to_string(const Yetani::SizePixel& size
10670  ) noexcept
10671 {
10672  return std::string()
10673  + "{ \"width\": " + std::to_string(size.width)
10674  + ", \"height\": " + std::to_string(size.height)
10675  + " }";
10676 }
10677 
10678 
10686 std::string to_string(const Yetani::WindowMode& window_mode
10687  ) noexcept
10688 {
10689  switch(window_mode)
10690  {
10691  case Yetani::WindowMode::Fullscreen: return "Fullscreen";
10692  case Yetani::WindowMode::Maximized: return "Maximized";
10693  case Yetani::WindowMode::Normal: return "Normal";
10694  default: return "";
10695  }
10696 }
10697 
10698 
10713  , Yetani::PointMm& rhs
10714  ) noexcept
10715 {
10716  return zakero::equalish(lhs.x, rhs.x, 0.001)
10717  && zakero::equalish(lhs.y, rhs.y, 0.001)
10718  ;
10719 }
10720 
10721 
10736  , Yetani::PointPercent& rhs
10737  ) noexcept
10738 {
10739  return zakero::equalish(lhs.x, rhs.x, 0.00001)
10740  && zakero::equalish(lhs.y, rhs.y, 0.00001)
10741  ;
10742 }
10743 
10744 
10756  , Yetani::PointPixel& rhs
10757  ) noexcept
10758 {
10759  return (lhs.x == rhs.x) && (lhs.y == rhs.y);
10760 }
10761 
10762 
10775  , Yetani::SizeMm& rhs
10776  ) noexcept
10777 {
10778  return zakero::equalish(lhs.width, rhs.width, 0.001)
10779  && zakero::equalish(lhs.height, rhs.height, 0.001)
10780  ;
10781 }
10782 
10783 
10796  , Yetani::SizePercent& rhs
10797  ) noexcept
10798 {
10799  return zakero::equalish(lhs.width, rhs.width, 0.00001)
10800  && zakero::equalish(lhs.height, rhs.height, 0.00001)
10801  ;
10802 }
10803 
10804 
10814  , Yetani::SizePixel& rhs
10815  ) noexcept
10816 {
10817  return (lhs.width == rhs.width) && (lhs.height == rhs.height);
10818 }
10819 
10820 // }}}
10821 
10822 }
10823 
10824 #endif // ZAKERO_YETANI_IMPLEMENTATION
10825 
10826 // }}}
10827 
10828 #endif // zakero_Yetani_h
Zakero Base.
std::string to_string(const bool value) noexcept
Convert a bool into a string.
Definition: Zakero_Base.h:534
#define ZAKERO_STEADY_TIME_NOW(unit_)
Get the current time.
Definition: Zakero_Base.h:205
auto vectorErase(std::vector< Type > &vector, const Type &value) noexcept
Erase the contents of a std::vector.
Definition: Zakero_Base.h:476
bool vectorContains(const std::vector< Type > &vector, const Type &value) noexcept
Check the contents of a std::vector.
Definition: Zakero_Base.h:404
uint64_t convert(const uint64_t size, const zakero::Storage from, const zakero::Storage to) noexcept
Convert storage sizes.
Definition: Zakero_Base.h:292
bool equalish(const float a, const float b, const float delta) noexcept
Compare two floats.
Definition: Zakero_Base.h:348
Zakero MemoryPool.
bool operator==(Xenium::PointMm &lhs, Xenium::PointMm &rhs) noexcept
Compare two Point objects.
Definition: Zakero_Xenium.h:8993
A pool of memory.
Definition: Zakero_MemoryPool.h:264
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:639
size_t size() const noexcept
The size of the memory pool.
Definition: Zakero_MemoryPool.h:746
int fd() const noexcept
The backing file descriptor.
Definition: Zakero_MemoryPool.h:733
void sizeOnChange(MemoryPool::LambdaSize) noexcept
Set the Size Event callback.
Definition: Zakero_MemoryPool.h:781
A Window.
Definition: Zakero_Yetani.h:1314
std::error_code sizeSet(const Yetani::SizeMm &) noexcept
Set the window size.
Definition: Zakero_Yetani.h:9059
void imagePresent() noexcept
Render the image.
Definition: Zakero_Yetani.h:9394
struct wl_shm_pool * wl_shm_pool
A pointer to the Wayland Shared Memory Pool.
Definition: Zakero_Yetani.h:1418
zakero::MemoryPool memory_pool
The Window's Memory Pool.
Definition: Zakero_Yetani.h:1419
void onCloseRequest(Yetani::Lambda) noexcept
Respond to "Close Request" events.
Definition: Zakero_Yetani.h:9662
void pointerOnEnter(Yetani::LambdaPointMm) noexcept
Respond to "Pointer Enter" events.
Definition: Zakero_Yetani.h:10015
void onFocusChange(Yetani::LambdaBool) noexcept
Respond to "Active" change events.
Definition: Zakero_Yetani.h:9716
uint32_t time() const noexcept
When the last frame was rendered.
Definition: Zakero_Yetani.h:9426
Yetani::PointPixel convertToPixel(const Yetani::PointMm &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9518
std::error_code decorationsSet(const Yetani::WindowDecorations) noexcept
Use the Desktop Environment borders.
Definition: Zakero_Yetani.h:8943
void windowModeOnChange(Yetani::LambdaWindowMode) noexcept
Respond to "Window Mode" events.
Definition: Zakero_Yetani.h:9818
virtual ~Window()
Destroy a Window.
Definition: Zakero_Yetani.h:8807
void pointerOnLeave(Yetani::Lambda) noexcept
Respond to "Pointer Leave" events.
Definition: Zakero_Yetani.h:10105
void cursorShow() noexcept
Show the cursor.
Definition: Zakero_Yetani.h:8880
void pointerOnButton(Yetani::LambdaButtonMm) noexcept
Respond to "Pointer Button" events.
Definition: Zakero_Yetani.h:9928
void pointerOnAxisSource(Yetani::Lambda) noexcept
Respond to "Pointer Axis Source" events.
Definition: Zakero_Yetani.h:10243
uint8_t bytesPerPixel() const noexcept
Get the number of bytes per pixel.
Definition: Zakero_Yetani.h:9444
void sizeOnChange(Yetani::LambdaSizeMm) noexcept
Respond to "Resize" events.
Definition: Zakero_Yetani.h:9847
std::error_code cursorUse(const std::string &) noexcept
Use a cursor.
Definition: Zakero_Yetani.h:8852
void keyboardOnEnter(Yetani::Lambda) noexcept
Respond to "Keyboard Enter" events.
Definition: Zakero_Yetani.h:9737
bool windowModeIs(const Yetani::WindowMode) noexcept
Check the WindowMode.
Definition: Zakero_Yetani.h:8989
std::error_code sizeSetMinMax(const Yetani::SizeMm &, const Yetani::SizeMm &) noexcept
Set the minimum window size.
Definition: Zakero_Yetani.h:9197
void titleSet(const std::string &) noexcept
Change the window title.
Definition: Zakero_Yetani.h:8917
void pointerOnMotion(Yetani::LambdaPointMm) noexcept
Respond to "Pointer Motion" events.
Definition: Zakero_Yetani.h:10133
Yetani::PointPercent convertToPercent(const Yetani::PointPixel &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9495
void classSet(const std::string &) noexcept
Change the window class.
Definition: Zakero_Yetani.h:8904
void pointerOnAxisDiscrete(Yetani::Lambda) noexcept
Respond to "Pointer Axis Discrete" events.
Definition: Zakero_Yetani.h:10297
void windowModeSet(const Yetani::WindowMode) noexcept
Change the window mode.
Definition: Zakero_Yetani.h:9013
Yetani::WindowMode windowMode() noexcept
Get the current WindowMode.
Definition: Zakero_Yetani.h:8971
std::error_code imageNext(uint8_t *&, Yetani::SizePixel &) noexcept
Get an image buffer.
Definition: Zakero_Yetani.h:9358
void pointerOnAxisStop(Yetani::Lambda) noexcept
Respond to "Pointer Axis Stop" events.
Definition: Zakero_Yetani.h:10270
void decorationsOnChange(Yetani::LambdaWindowDecorations) noexcept
Respond to "Decoration Change" events.
Definition: Zakero_Yetani.h:9687
Window(void *)
Construct a Window.
Definition: Zakero_Yetani.h:8754
void keyboardOnKey(Yetani::LambdaKey) noexcept
Respond to "Keyboard Key" events.
Definition: Zakero_Yetani.h:9791
void cursorHide() noexcept
Hide the cursor.
Definition: Zakero_Yetani.h:8869
void minimize() noexcept
Minimize the window.
Definition: Zakero_Yetani.h:9457
Yetani::PointMm convertToMm(const Yetani::PointPixel &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9472
void pointerOnAxis(Yetani::LambdaAxis) noexcept
Respond to "Pointer Axis" events.
Definition: Zakero_Yetani.h:10216
void keyboardOnLeave(Yetani::Lambda) noexcept
Respond to "Keyboard Leave" events.
Definition: Zakero_Yetani.h:9763
The shared memory.
Definition: Zakero_Yetani.h:1417
A wrapper class for Wayland.
Definition: Zakero_Yetani.h:1027
uint32_t code
The key code of the event.
Definition: Zakero_Yetani.h:1047
std::string make
Description of the manufacturer.
Definition: Zakero_Yetani.h:1200
static std::string outputTransformName(int32_t) noexcept
Get a human readable string.
Definition: Zakero_Yetani.h:4785
float pixels_per_mm_vertical
A pre-calculated value.
Definition: Zakero_Yetani.h:1214
std::function< void(const Yetani::Key &, const Yetani::KeyModifier &)> LambdaKey
A Lambda that has parameters: Key and KeyModifier.
Definition: Zakero_Yetani.h:1296
static std::string outputSubpixelName(int32_t) noexcept
Get a human readable string.
Definition: Zakero_Yetani.h:4760
float pixels_per_mm_horizontal
A pre-calculated value.
Definition: Zakero_Yetani.h:1213
float distance
The distance traveled.
Definition: Zakero_Yetani.h:1117
const std::vector< void * > & image_data
A collection of image data.
Definition: Zakero_Yetani.h:1181
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:1299
static std::string shmFormatName(const wl_shm_format) noexcept
Get the name of the format.
Definition: Zakero_Yetani.h:4485
Yetani::VectorOutputId outputVector() const noexcept
Get a list of the Output Id's.
Definition: Zakero_Yetani.h:4734
int32_t height
The height of the device in hardware units.
Definition: Zakero_Yetani.h:1205
int32_t keyRepeatDelay() const noexcept
The key repeat delay.
Definition: Zakero_Yetani.h:5445
static constexpr uint32_t KeyModifier_Alt
Key Modifier flag.
Definition: Zakero_Yetani.h:1054
uint32_t pressed
A collection of pressed modifiers.
Definition: Zakero_Yetani.h:1060
void outputOnAdd(Yetani::LambdaOutputId) noexcept
Notification of adding an Output device.
Definition: Zakero_Yetani.h:5046
Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointMm &) const noexcept
Convert Millimeter to Pixel.
Definition: Zakero_Yetani.h:4869
Yetani::PointerAxisType type
The type of Axis.
Definition: Zakero_Yetani.h:1119
static constexpr uint32_t KeyModifier_Meta
Key Modifier flag.
Definition: Zakero_Yetani.h:1056
Yetani::PointPercent outputConvertToPercent(const Yetani::OutputId, const Yetani::PointPixel &) const noexcept
Convert Pixel to a Percentage.
Definition: Zakero_Yetani.h:4839
Yetani::Output output(const Yetani::OutputId) const noexcept
Get a copy of the Output information.
Definition: Zakero_Yetani.h:4702
int32_t y
The Y position within the global compositor.
Definition: Zakero_Yetani.h:1203
Yetani::Window * windowCreate(const Yetani::SizeMm &, std::error_code &) noexcept
Create a window.
Definition: Zakero_Yetani.h:8018
PointerAxisType
The direction of the axis movement.
Definition: Zakero_Yetani.h:1108
void outputOnChange(Yetani::LambdaOutputId) noexcept
Notification that an Output device has changed.
Definition: Zakero_Yetani.h:5069
Yetani::PointerButtonState state
The button state.
Definition: Zakero_Yetani.h:1133
PointerButtonState
Mouse button state.
Definition: Zakero_Yetani.h:1126
uint32_t time
When the key event happened.
Definition: Zakero_Yetani.h:1046
std::function< void(Yetani::WindowMode)> LambdaWindowMode
A Lambda that has a parameter: WindowMode.
Definition: Zakero_Yetani.h:1306
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:1300
uint32_t flags
wl_output_mode bitfield properties.
Definition: Zakero_Yetani.h:1212
static constexpr wl_shm_format SHM_FORMAT_DEFAULT
The default pixel format.
Definition: Zakero_Yetani.h:1438
static constexpr uint32_t KeyModifier_CapsLock
Key Modifier flag.
Definition: Zakero_Yetani.h:1052
void outputOnRemove(Yetani::LambdaOutputId) noexcept
Notification of removing an Output device.
Definition: Zakero_Yetani.h:5092
PointerAxisSource
Where the axis information came from.
Definition: Zakero_Yetani.h:1100
std::function< void(const Yetani::PointerAxis &, const Yetani::KeyModifier &)> LambdaAxis
A Lambda that has parameters: PointerAxis and KeyModifier.
Definition: Zakero_Yetani.h:1297
std::function< void(const Yetani::PointMm &, const Yetani::KeyModifier &)> LambdaPointMm
A Lambda that has parameters: PointMm and KeyModifier.
Definition: Zakero_Yetani.h:1301
uint32_t latched
A collection of latched modifiers.
Definition: Zakero_Yetani.h:1061
static Yetani * connect() noexcept
Establish a connection with the Wayland Compositor.
Definition: Zakero_Yetani.h:3312
std::error_code cursorCreate(const std::string &, const Yetani::CursorConfig &) noexcept
Create a cursor.
Definition: Zakero_Yetani.h:3795
std::function< void(const Yetani::PointPercent &, const Yetani::KeyModifier &)> LambdaPointPercent
A Lambda that has parameters: PointPercent and KeyModifier.
Definition: Zakero_Yetani.h:1302
std::function< void()> Lambda
A Lambda that has no parameters.
Definition: Zakero_Yetani.h:1295
uint32_t physical_height_mm
The height of the device in millimeters.
Definition: Zakero_Yetani.h:1207
uint32_t physical_width_mm
The width of the device in millimeters.
Definition: Zakero_Yetani.h:1206
int32_t keyRepeatRate() const noexcept
The key repeat rate.
Definition: Zakero_Yetani.h:5459
std::function< void(const Yetani::SizeMm &)> LambdaSizeMm
A Lambda that has a parameter: SizeMm.
Definition: Zakero_Yetani.h:1307
std::string model
Description of the model.
Definition: Zakero_Yetani.h:1201
const Yetani::VectorShmFormat & shmFormatAvailable() const noexcept
Get all the support color formats.
Definition: Zakero_Yetani.h:4420
std::error_code cursorDestroy(const std::string &) noexcept
Destroy a cursor.
Definition: Zakero_Yetani.h:3933
std::function< void(const Yetani::SizePercent &)> LambdaSizePercent
A Lambda that has a parameter: SizePercent.
Definition: Zakero_Yetani.h:1308
WindowDecorations
Who is responsible for rendering the decorations.
Definition: Zakero_Yetani.h:1283
KeyState
Keyboard key state
Definition: Zakero_Yetani.h:1039
int32_t refresh_mHz
The current refresh rate of the device.
Definition: Zakero_Yetani.h:1209
uint32_t time
When the event occurred.
Definition: Zakero_Yetani.h:1115
int32_t x
The X position within the global compositor.
Definition: Zakero_Yetani.h:1202
int32_t width
The width of the device in hardware units.
Definition: Zakero_Yetani.h:1204
uint32_t group
The keyboard layout.
Definition: Zakero_Yetani.h:1063
std::function< void(const Yetani::PointPixel &, const Yetani::KeyModifier &)> LambdaPointPixel
A Lambda that has parameters: PointPixel and KeyModifier.
Definition: Zakero_Yetani.h:1303
int32_t scale_factor
The scaling factor between the device and compositor.
Definition: Zakero_Yetani.h:1210
std::function< void(bool)> LambdaBool
A Lambda that has a parameter: bool.
Definition: Zakero_Yetani.h:1304
virtual ZAKERO_YETANI__ERROR_DATA ~Yetani() noexcept
Destructor.
Definition: Zakero_Yetani.h:3276
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:1298
WindowMode
Definition: Zakero_Yetani.h:1288
int32_t steps
The number of rotation steps.
Definition: Zakero_Yetani.h:1116
KeyState state
The state of the key.
Definition: Zakero_Yetani.h:1048
std::function< void(const Yetani::SizePixel &)> LambdaSizePixel
A Lambda that has a parameter: SizePixel.
Definition: Zakero_Yetani.h:1309
int32_t subpixel
The device's subpixel orientation.
Definition: Zakero_Yetani.h:1208
std::function< void(Yetani::WindowDecorations)> LambdaWindowDecorations
A Lambda that has a parameter: WindowDecorations.
Definition: Zakero_Yetani.h:1305
static constexpr uint32_t KeyModifier_Control
Key Modifier flag.
Definition: Zakero_Yetani.h:1053
static uint8_t shmFormatBytesPerPixel(const wl_shm_format) noexcept
Determine bytes-per-pixel.
Definition: Zakero_Yetani.h:4437
static constexpr uint32_t KeyModifier_Shift
Key Modifier flag.
Definition: Zakero_Yetani.h:1051
uint32_t code
The event code.
Definition: Zakero_Yetani.h:1132
Yetani::PointMm outputConvertToMm(const Yetani::OutputId, const Yetani::PointPixel &) const noexcept
Convert Pixel to Millimeter.
Definition: Zakero_Yetani.h:4809
Yetani::PointerAxisSource source
The source of the event.
Definition: Zakero_Yetani.h:1118
int32_t transform
Transform that maps framebuffer to output.
Definition: Zakero_Yetani.h:1211
static std::string shmFormatDescription(const wl_shm_format) noexcept
Get a description of the format.
Definition: Zakero_Yetani.h:4462
uint32_t locked
A collection of locked modifiers.
Definition: Zakero_Yetani.h:1062
Cursor configuration.
Definition: Zakero_Yetani.h:1175
Key event information.
Definition: Zakero_Yetani.h:1045
A collection modifier flags.
Definition: Zakero_Yetani.h:1059
Information about a output device.
Definition: Zakero_Yetani.h:1199
Information about an Axis event.
Definition: Zakero_Yetani.h:1114
Information about a pointer button event.
Definition: Zakero_Yetani.h:1131
A location that uses millimeters.
Definition: Zakero_Yetani.h:1070
float x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1072
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1071
float y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1073
friend bool operator==(Yetani::PointMm &, Yetani::PointMm &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10712
A location that uses percentages.
Definition: Zakero_Yetani.h:1079
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1080
float x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1081
friend bool operator==(Yetani::PointPercent &, Yetani::PointPercent &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10735
float y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1082
A location that uses pixels.
Definition: Zakero_Yetani.h:1088
friend bool operator==(Yetani::PointPixel &, Yetani::PointPixel &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10755
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1089
int32_t x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1090
int32_t y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1091
Size measured in millimeters.
Definition: Zakero_Yetani.h:1140
friend bool operator==(Yetani::SizeMm &, Yetani::SizeMm &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10774
float width
The width.
Definition: Zakero_Yetani.h:1141
float height
The height.
Definition: Zakero_Yetani.h:1142
Size measured as a percentage of the Output (Monitor) resolution.
Definition: Zakero_Yetani.h:1148
float width
The width.
Definition: Zakero_Yetani.h:1149
float height
The height.
Definition: Zakero_Yetani.h:1150
friend bool operator==(Yetani::SizePercent &, Yetani::SizePercent &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10795
Size measured in pixels.
Definition: Zakero_Yetani.h:1156
friend bool operator==(Yetani::SizePixel &, Yetani::SizePixel &) noexcept
Compare two Size objects.
Definition: Zakero_Yetani.h:10813
int32_t width
The width.
Definition: Zakero_Yetani.h:1157
int32_t height
The height.
Definition: Zakero_Yetani.h:1158