Zakero's C++ Header Libraries
A collection of reusable C++ libraries
Zakero_Yetani.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2010-2019 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 
211 /******************************************************************************
212  * Includes
213  */
214 
215 #include <iostream>
216 #include <thread>
217 
218 // POSIX
219 #include <poll.h>
220 
221 // Linux
222 #include <linux/input-event-codes.h>
223 
224 // Wayland
225 #include <wayland/wayland-client.h>
226 
227 // Zakero
228 #include "Zakero_Base.h"
229 #include "Zakero_MemoryPool.h"
230 
231 
232 /******************************************************************************
233  * Macros
234  */
235 
236 // {{{ Macros
237 
254 #define ZAKERO_YETANI__ERROR_DATA \
255  X(Error_None , 0 , "No Error" ) \
256  X(Error_Compositor_Was_Not_Found , 1 , "Could not find the Compositor object in the Global Repository." ) \
257  X(Error_Connection_Failed , 2 , "Failed to connect to the Wayland Server." ) \
258  X(Error_Cursor_Already_Exists , 3 , "A cursor with that name already exists." ) \
259  X(Error_Cursor_Does_Not_Exist , 4 , "No cursors exists with that name." ) \
260  X(Error_Cursor_Frame_Time_Too_Large , 5 , "The cursor time per frame is too large, must be <= Size_Max." ) \
261  X(Error_Cursor_Frame_Time_Too_Small , 6 , "The cursor time per frame is too small, must be greater than 0." ) \
262  X(Error_Cursor_Image_Data_Is_Empty , 7 , "The cursor image data can not be empty." ) \
263  X(Error_Cursor_Name_Is_Invalid , 8 , "The cursor name is invalid." ) \
264  X(Error_Cursor_Not_Attached , 9 , "The specified cursor is not attached/in-use." ) \
265  X(Error_Cursor_Size_Too_Small , 10 , "The cursor size, both width and height must be greater than 0." ) \
266  X(Error_Invalid_Display_Name , 11 , "An invalid dispaly name was given to the Wayland Server." ) \
267  X(Error_Minimum_Size_Greater_Than_Maximum_Size , 12 , "The minimum window size is larger than the maximum window size." ) \
268  X(Error_No_Output_Available , 13 , "No output devices are available." ) \
269  X(Error_Registry_Not_Available , 14 , "Unable to get the registery." ) \
270  X(Error_Server_Side_Decorations_Not_Available , 15 , "The Wayland Compositor does not support Server Side Decorations." ) \
271  X(Error_Shm_Was_Not_Found , 16 , "Could not find the Shm object in the Global Repository." ) \
272  X(Error_Wayland_Not_Available , 17 , "Could not find the Wayland Server." ) \
273  X(Error_Window_Initialization_Failed , 18 , "The window was not able to be initialized." ) \
274  X(Error_Window_Size_Too_Small , 19 , "The window size was too small." ) \
275  X(Error_Xdg_WM_Base_Was_Not_Found , 20 , "Could not find the XDG WM Base object the Global Repository." ) \
276 
277  /* --- To Be Deleted --- */
278  /*
279  X(Error_Window_Already_Exists , 100 , "A window with that name already exists." ) \
280  X(Error_Window_Does_Not_Exist , 101 , "No windows exists with that name." ) \
281  X(Error_Window_Name_Can_Not_Be_Empty , 102 , "Windows can not have empty names." ) \
282  X(Error_EventLoop_Is_Already_Running , 103 , "Can't start the event loop since it is already running." ) \
283  X(Error_Connection_Not_Initialized , 104 , "Not connected to the Wayland Server." ) \
284  X(Error_Connection_Already_Established , 105 , "Must disconnect before establishing a new connection." ) \
285  X(Error_Seat_Was_Not_Found , 106 , "Could not find the Seat object in the Global Repository." ) \
286  X(Error_Present_Current_Image_First , 107 , "The next image has already been retrieved and must be presented." ) \
287  X(Error_No_Image_Is_Available , 108 , "No image is available to be retrieved." ) \
288  X(Error_Window_Is_Locked , 109 , "The window access is restricted due to being locked." ) \
289  X(Error_Cursor_Image_Data_Size_Is_Invalid , 110 , "The cursor image data size does not match the configuration." ) \
290  */
291 
292 // }}}
293 
294 /******************************************************************************
295  * Generated Code
296  *
297  * The code is this section was created by "wayland-protocol/protocol.sh". The
298  * generated code is required since the XDG/Wayland headers are not officially
299  * distributed. Plus, there are many versions of the generated code with
300  * slight variations. By including the code directly, the generated code is
301  * from a known baseline.
302  *
303  * The "wayland-protocol/protocol.sh" script uses the "// {{{ Generated Code",
304  * plus matching "// }}}" as markers to know where to add and remove code.
305  *
306  * TL;DR: The code you are looking for is in the Yetani class.
307  */
308 
313 // {{{ Generated Code
314 // {{{ xdg-decoration-unstable-v1
315 struct xdg_toplevel;
316 struct zxdg_decoration_manager_v1;
317 struct zxdg_toplevel_decoration_v1;
318 extern const struct wl_interface zxdg_decoration_manager_v1_interface;
319 extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
320 static inline void
321 zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data)
322 {
323  wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data);
324 }
325 static inline void *
326 zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
327 {
328  return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1);
329 }
330 static inline uint32_t
331 zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
332 {
333  return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1);
334 }
335 static inline void
336 zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
337 {
338  wl_proxy_marshal((struct wl_proxy *) zxdg_decoration_manager_v1,
339  0);
340  wl_proxy_destroy((struct wl_proxy *) zxdg_decoration_manager_v1);
341 }
342 static inline struct zxdg_toplevel_decoration_v1 *
343 zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel)
344 {
345  struct wl_proxy *id;
346  id = wl_proxy_marshal_constructor((struct wl_proxy *) zxdg_decoration_manager_v1,
347  1, &zxdg_toplevel_decoration_v1_interface, NULL, toplevel);
348  return (struct zxdg_toplevel_decoration_v1 *) id;
349 }
350 enum zxdg_toplevel_decoration_v1_error {
351  ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0,
352  ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1,
353  ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2,
354 };
355 enum zxdg_toplevel_decoration_v1_mode {
356  ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1,
357  ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2,
358 };
359 struct zxdg_toplevel_decoration_v1_listener {
360  void (*configure)(void *data,
361  struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
362  uint32_t mode);
363 };
364 static inline int
365 zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
366  const struct zxdg_toplevel_decoration_v1_listener *listener, void *data)
367 {
368  return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1,
369  (void (**)(void)) listener, data);
370 }
371 static inline void
372 zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data)
373 {
374  wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data);
375 }
376 static inline void *
377 zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
378 {
379  return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1);
380 }
381 static inline uint32_t
382 zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
383 {
384  return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1);
385 }
386 static inline void
387 zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
388 {
389  wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
390  0);
391  wl_proxy_destroy((struct wl_proxy *) zxdg_toplevel_decoration_v1);
392 }
393 static inline void
394 zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode)
395 {
396  wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
397  1, mode);
398 }
399 static inline void
400 zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
401 {
402  wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
403  2);
404 }
405 extern const struct wl_interface xdg_toplevel_interface;
406 extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
407 static const struct wl_interface *xdg_decoration_unstable_v1_types[] = {
408  NULL,
409  &zxdg_toplevel_decoration_v1_interface,
410  &xdg_toplevel_interface,
411 };
412 static const struct wl_message zxdg_decoration_manager_v1_requests[] = {
413  { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
414  { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 },
415 };
416 const struct wl_interface zxdg_decoration_manager_v1_interface = {
417  "zxdg_decoration_manager_v1", 1,
418  2, zxdg_decoration_manager_v1_requests,
419  0, NULL,
420 };
421 static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = {
422  { "destroy", "", xdg_decoration_unstable_v1_types + 0 },
423  { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 },
424  { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 },
425 };
426 static const struct wl_message zxdg_toplevel_decoration_v1_events[] = {
427  { "configure", "u", xdg_decoration_unstable_v1_types + 0 },
428 };
429 const struct wl_interface zxdg_toplevel_decoration_v1_interface = {
430  "zxdg_toplevel_decoration_v1", 1,
431  3, zxdg_toplevel_decoration_v1_requests,
432  1, zxdg_toplevel_decoration_v1_events,
433 };
434 // }}}
435 // {{{ xdg-shell
436 struct wl_output;
437 struct wl_seat;
438 struct wl_surface;
439 struct xdg_popup;
440 struct xdg_positioner;
441 struct xdg_surface;
442 struct xdg_toplevel;
443 struct xdg_wm_base;
444 extern const struct wl_interface xdg_wm_base_interface;
445 extern const struct wl_interface xdg_positioner_interface;
446 extern const struct wl_interface xdg_surface_interface;
447 extern const struct wl_interface xdg_toplevel_interface;
448 extern const struct wl_interface xdg_popup_interface;
449 enum xdg_wm_base_error {
450  XDG_WM_BASE_ERROR_ROLE = 0,
451  XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1,
452  XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2,
453  XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3,
454  XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4,
455  XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5,
456 };
457 struct xdg_wm_base_listener {
458  void (*ping)(void *data,
459  struct xdg_wm_base *xdg_wm_base,
460  uint32_t serial);
461 };
462 static inline int
463 xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base,
464  const struct xdg_wm_base_listener *listener, void *data)
465 {
466  return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base,
467  (void (**)(void)) listener, data);
468 }
469 static inline void
470 xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data)
471 {
472  wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data);
473 }
474 static inline void *
475 xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base)
476 {
477  return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base);
478 }
479 static inline uint32_t
480 xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base)
481 {
482  return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base);
483 }
484 static inline void
485 xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base)
486 {
487  wl_proxy_marshal((struct wl_proxy *) xdg_wm_base,
488  0);
489  wl_proxy_destroy((struct wl_proxy *) xdg_wm_base);
490 }
491 static inline struct xdg_positioner *
492 xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base)
493 {
494  struct wl_proxy *id;
495  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base,
496  1, &xdg_positioner_interface, NULL);
497  return (struct xdg_positioner *) id;
498 }
499 static inline struct xdg_surface *
500 xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface)
501 {
502  struct wl_proxy *id;
503  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base,
504  2, &xdg_surface_interface, NULL, surface);
505  return (struct xdg_surface *) id;
506 }
507 static inline void
508 xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial)
509 {
510  wl_proxy_marshal((struct wl_proxy *) xdg_wm_base,
511  3, serial);
512 }
513 enum xdg_positioner_error {
514  XDG_POSITIONER_ERROR_INVALID_INPUT = 0,
515 };
516 enum xdg_positioner_anchor {
517  XDG_POSITIONER_ANCHOR_NONE = 0,
518  XDG_POSITIONER_ANCHOR_TOP = 1,
519  XDG_POSITIONER_ANCHOR_BOTTOM = 2,
520  XDG_POSITIONER_ANCHOR_LEFT = 3,
521  XDG_POSITIONER_ANCHOR_RIGHT = 4,
522  XDG_POSITIONER_ANCHOR_TOP_LEFT = 5,
523  XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6,
524  XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7,
525  XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8,
526 };
527 enum xdg_positioner_gravity {
528  XDG_POSITIONER_GRAVITY_NONE = 0,
529  XDG_POSITIONER_GRAVITY_TOP = 1,
530  XDG_POSITIONER_GRAVITY_BOTTOM = 2,
531  XDG_POSITIONER_GRAVITY_LEFT = 3,
532  XDG_POSITIONER_GRAVITY_RIGHT = 4,
533  XDG_POSITIONER_GRAVITY_TOP_LEFT = 5,
534  XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6,
535  XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7,
536  XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8,
537 };
538 enum xdg_positioner_constraint_adjustment {
539  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0,
540  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1,
541  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2,
542  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4,
543  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8,
544  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16,
545  XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32,
546 };
547 static inline void
548 xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data)
549 {
550  wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data);
551 }
552 static inline void *
553 xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner)
554 {
555  return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner);
556 }
557 static inline uint32_t
558 xdg_positioner_get_version(struct xdg_positioner *xdg_positioner)
559 {
560  return wl_proxy_get_version((struct wl_proxy *) xdg_positioner);
561 }
562 static inline void
563 xdg_positioner_destroy(struct xdg_positioner *xdg_positioner)
564 {
565  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
566  0);
567  wl_proxy_destroy((struct wl_proxy *) xdg_positioner);
568 }
569 static inline void
570 xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height)
571 {
572  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
573  1, width, height);
574 }
575 static inline void
576 xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height)
577 {
578  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
579  2, x, y, width, height);
580 }
581 static inline void
582 xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor)
583 {
584  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
585  3, anchor);
586 }
587 static inline void
588 xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity)
589 {
590  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
591  4, gravity);
592 }
593 static inline void
594 xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment)
595 {
596  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
597  5, constraint_adjustment);
598 }
599 static inline void
600 xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y)
601 {
602  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
603  6, x, y);
604 }
605 static inline void
606 xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner)
607 {
608  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
609  7);
610 }
611 static inline void
612 xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height)
613 {
614  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
615  8, parent_width, parent_height);
616 }
617 static inline void
618 xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial)
619 {
620  wl_proxy_marshal((struct wl_proxy *) xdg_positioner,
621  9, serial);
622 }
623 enum xdg_surface_error {
624  XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1,
625  XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2,
626  XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3,
627 };
628 struct xdg_surface_listener {
629  void (*configure)(void *data,
630  struct xdg_surface *xdg_surface,
631  uint32_t serial);
632 };
633 static inline int
634 xdg_surface_add_listener(struct xdg_surface *xdg_surface,
635  const struct xdg_surface_listener *listener, void *data)
636 {
637  return wl_proxy_add_listener((struct wl_proxy *) xdg_surface,
638  (void (**)(void)) listener, data);
639 }
640 static inline void
641 xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)
642 {
643  wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data);
644 }
645 static inline void *
646 xdg_surface_get_user_data(struct xdg_surface *xdg_surface)
647 {
648  return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface);
649 }
650 static inline uint32_t
651 xdg_surface_get_version(struct xdg_surface *xdg_surface)
652 {
653  return wl_proxy_get_version((struct wl_proxy *) xdg_surface);
654 }
655 static inline void
656 xdg_surface_destroy(struct xdg_surface *xdg_surface)
657 {
658  wl_proxy_marshal((struct wl_proxy *) xdg_surface,
659  0);
660  wl_proxy_destroy((struct wl_proxy *) xdg_surface);
661 }
662 static inline struct xdg_toplevel *
663 xdg_surface_get_toplevel(struct xdg_surface *xdg_surface)
664 {
665  struct wl_proxy *id;
666  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface,
667  1, &xdg_toplevel_interface, NULL);
668  return (struct xdg_toplevel *) id;
669 }
670 static inline struct xdg_popup *
671 xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner)
672 {
673  struct wl_proxy *id;
674  id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface,
675  2, &xdg_popup_interface, NULL, parent, positioner);
676  return (struct xdg_popup *) id;
677 }
678 static inline void
679 xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height)
680 {
681  wl_proxy_marshal((struct wl_proxy *) xdg_surface,
682  3, x, y, width, height);
683 }
684 static inline void
685 xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)
686 {
687  wl_proxy_marshal((struct wl_proxy *) xdg_surface,
688  4, serial);
689 }
690 enum xdg_toplevel_resize_edge {
691  XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0,
692  XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1,
693  XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2,
694  XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4,
695  XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5,
696  XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6,
697  XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8,
698  XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9,
699  XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10,
700 };
701 enum xdg_toplevel_state {
702  XDG_TOPLEVEL_STATE_MAXIMIZED = 1,
703  XDG_TOPLEVEL_STATE_FULLSCREEN = 2,
704  XDG_TOPLEVEL_STATE_RESIZING = 3,
705  XDG_TOPLEVEL_STATE_ACTIVATED = 4,
706  XDG_TOPLEVEL_STATE_TILED_LEFT = 5,
707  XDG_TOPLEVEL_STATE_TILED_RIGHT = 6,
708  XDG_TOPLEVEL_STATE_TILED_TOP = 7,
709  XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8,
710 };
711 struct xdg_toplevel_listener {
712  void (*configure)(void *data,
713  struct xdg_toplevel *xdg_toplevel,
714  int32_t width,
715  int32_t height,
716  struct wl_array *states);
717  void (*close)(void *data,
718  struct xdg_toplevel *xdg_toplevel);
719 };
720 static inline int
721 xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel,
722  const struct xdg_toplevel_listener *listener, void *data)
723 {
724  return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel,
725  (void (**)(void)) listener, data);
726 }
727 static inline void
728 xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data)
729 {
730  wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data);
731 }
732 static inline void *
733 xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel)
734 {
735  return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel);
736 }
737 static inline uint32_t
738 xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel)
739 {
740  return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel);
741 }
742 static inline void
743 xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel)
744 {
745  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
746  0);
747  wl_proxy_destroy((struct wl_proxy *) xdg_toplevel);
748 }
749 static inline void
750 xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent)
751 {
752  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
753  1, parent);
754 }
755 static inline void
756 xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title)
757 {
758  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
759  2, title);
760 }
761 static inline void
762 xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id)
763 {
764  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
765  3, app_id);
766 }
767 static inline void
768 xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
769 {
770  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
771  4, seat, serial, x, y);
772 }
773 static inline void
774 xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial)
775 {
776  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
777  5, seat, serial);
778 }
779 static inline void
780 xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges)
781 {
782  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
783  6, seat, serial, edges);
784 }
785 static inline void
786 xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
787 {
788  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
789  7, width, height);
790 }
791 static inline void
792 xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
793 {
794  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
795  8, width, height);
796 }
797 static inline void
798 xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel)
799 {
800  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
801  9);
802 }
803 static inline void
804 xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel)
805 {
806  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
807  10);
808 }
809 static inline void
810 xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output)
811 {
812  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
813  11, output);
814 }
815 static inline void
816 xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel)
817 {
818  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
819  12);
820 }
821 static inline void
822 xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel)
823 {
824  wl_proxy_marshal((struct wl_proxy *) xdg_toplevel,
825  13);
826 }
827 enum xdg_popup_error {
828  XDG_POPUP_ERROR_INVALID_GRAB = 0,
829 };
830 struct xdg_popup_listener {
831  void (*configure)(void *data,
832  struct xdg_popup *xdg_popup,
833  int32_t x,
834  int32_t y,
835  int32_t width,
836  int32_t height);
837  void (*popup_done)(void *data,
838  struct xdg_popup *xdg_popup);
839  void (*repositioned)(void *data,
840  struct xdg_popup *xdg_popup,
841  uint32_t token);
842 };
843 static inline int
844 xdg_popup_add_listener(struct xdg_popup *xdg_popup,
845  const struct xdg_popup_listener *listener, void *data)
846 {
847  return wl_proxy_add_listener((struct wl_proxy *) xdg_popup,
848  (void (**)(void)) listener, data);
849 }
850 static inline void
851 xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data)
852 {
853  wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data);
854 }
855 static inline void *
856 xdg_popup_get_user_data(struct xdg_popup *xdg_popup)
857 {
858  return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup);
859 }
860 static inline uint32_t
861 xdg_popup_get_version(struct xdg_popup *xdg_popup)
862 {
863  return wl_proxy_get_version((struct wl_proxy *) xdg_popup);
864 }
865 static inline void
866 xdg_popup_destroy(struct xdg_popup *xdg_popup)
867 {
868  wl_proxy_marshal((struct wl_proxy *) xdg_popup,
869  0);
870  wl_proxy_destroy((struct wl_proxy *) xdg_popup);
871 }
872 static inline void
873 xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial)
874 {
875  wl_proxy_marshal((struct wl_proxy *) xdg_popup,
876  1, seat, serial);
877 }
878 static inline void
879 xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token)
880 {
881  wl_proxy_marshal((struct wl_proxy *) xdg_popup,
882  2, positioner, token);
883 }
884 extern const struct wl_interface wl_output_interface;
885 extern const struct wl_interface wl_seat_interface;
886 extern const struct wl_interface wl_surface_interface;
887 extern const struct wl_interface xdg_popup_interface;
888 extern const struct wl_interface xdg_positioner_interface;
889 extern const struct wl_interface xdg_surface_interface;
890 extern const struct wl_interface xdg_toplevel_interface;
891 static const struct wl_interface *xdg_shell_types[] = {
892  NULL,
893  NULL,
894  NULL,
895  NULL,
896  &xdg_positioner_interface,
897  &xdg_surface_interface,
898  &wl_surface_interface,
899  &xdg_toplevel_interface,
900  &xdg_popup_interface,
901  &xdg_surface_interface,
902  &xdg_positioner_interface,
903  &xdg_toplevel_interface,
904  &wl_seat_interface,
905  NULL,
906  NULL,
907  NULL,
908  &wl_seat_interface,
909  NULL,
910  &wl_seat_interface,
911  NULL,
912  NULL,
913  &wl_output_interface,
914  &wl_seat_interface,
915  NULL,
916  &xdg_positioner_interface,
917  NULL,
918 };
919 static const struct wl_message xdg_wm_base_requests[] = {
920  { "destroy", "", xdg_shell_types + 0 },
921  { "create_positioner", "n", xdg_shell_types + 4 },
922  { "get_xdg_surface", "no", xdg_shell_types + 5 },
923  { "pong", "u", xdg_shell_types + 0 },
924 };
925 static const struct wl_message xdg_wm_base_events[] = {
926  { "ping", "u", xdg_shell_types + 0 },
927 };
928 const struct wl_interface xdg_wm_base_interface = {
929  "xdg_wm_base", 3,
930  4, xdg_wm_base_requests,
931  1, xdg_wm_base_events,
932 };
933 static const struct wl_message xdg_positioner_requests[] = {
934  { "destroy", "", xdg_shell_types + 0 },
935  { "set_size", "ii", xdg_shell_types + 0 },
936  { "set_anchor_rect", "iiii", xdg_shell_types + 0 },
937  { "set_anchor", "u", xdg_shell_types + 0 },
938  { "set_gravity", "u", xdg_shell_types + 0 },
939  { "set_constraint_adjustment", "u", xdg_shell_types + 0 },
940  { "set_offset", "ii", xdg_shell_types + 0 },
941  { "set_reactive", "3", xdg_shell_types + 0 },
942  { "set_parent_size", "3ii", xdg_shell_types + 0 },
943  { "set_parent_configure", "3u", xdg_shell_types + 0 },
944 };
945 const struct wl_interface xdg_positioner_interface = {
946  "xdg_positioner", 3,
947  10, xdg_positioner_requests,
948  0, NULL,
949 };
950 static const struct wl_message xdg_surface_requests[] = {
951  { "destroy", "", xdg_shell_types + 0 },
952  { "get_toplevel", "n", xdg_shell_types + 7 },
953  { "get_popup", "n?oo", xdg_shell_types + 8 },
954  { "set_window_geometry", "iiii", xdg_shell_types + 0 },
955  { "ack_configure", "u", xdg_shell_types + 0 },
956 };
957 static const struct wl_message xdg_surface_events[] = {
958  { "configure", "u", xdg_shell_types + 0 },
959 };
960 const struct wl_interface xdg_surface_interface = {
961  "xdg_surface", 3,
962  5, xdg_surface_requests,
963  1, xdg_surface_events,
964 };
965 static const struct wl_message xdg_toplevel_requests[] = {
966  { "destroy", "", xdg_shell_types + 0 },
967  { "set_parent", "?o", xdg_shell_types + 11 },
968  { "set_title", "s", xdg_shell_types + 0 },
969  { "set_app_id", "s", xdg_shell_types + 0 },
970  { "show_window_menu", "ouii", xdg_shell_types + 12 },
971  { "move", "ou", xdg_shell_types + 16 },
972  { "resize", "ouu", xdg_shell_types + 18 },
973  { "set_max_size", "ii", xdg_shell_types + 0 },
974  { "set_min_size", "ii", xdg_shell_types + 0 },
975  { "set_maximized", "", xdg_shell_types + 0 },
976  { "unset_maximized", "", xdg_shell_types + 0 },
977  { "set_fullscreen", "?o", xdg_shell_types + 21 },
978  { "unset_fullscreen", "", xdg_shell_types + 0 },
979  { "set_minimized", "", xdg_shell_types + 0 },
980 };
981 static const struct wl_message xdg_toplevel_events[] = {
982  { "configure", "iia", xdg_shell_types + 0 },
983  { "close", "", xdg_shell_types + 0 },
984 };
985 const struct wl_interface xdg_toplevel_interface = {
986  "xdg_toplevel", 3,
987  14, xdg_toplevel_requests,
988  2, xdg_toplevel_events,
989 };
990 static const struct wl_message xdg_popup_requests[] = {
991  { "destroy", "", xdg_shell_types + 0 },
992  { "grab", "ou", xdg_shell_types + 22 },
993  { "reposition", "3ou", xdg_shell_types + 24 },
994 };
995 static const struct wl_message xdg_popup_events[] = {
996  { "configure", "iiii", xdg_shell_types + 0 },
997  { "popup_done", "", xdg_shell_types + 0 },
998  { "repositioned", "3u", xdg_shell_types + 0 },
999 };
1000 const struct wl_interface xdg_popup_interface = {
1001  "xdg_popup", 3,
1002  3, xdg_popup_requests,
1003  3, xdg_popup_events,
1004 };
1005 // }}}
1006 // }}}
1007 
1012 namespace zakero
1013 {
1014  // {{{ Declaration
1015 
1016  class Yetani
1017  {
1018  public:
1019 #define X(name_, val_, mesg_) \
1020  static constexpr int name_ = val_;
1021  ZAKERO_YETANI__ERROR_DATA
1022 #undef X
1023 
1024  virtual ~Yetani() noexcept;
1025 
1026  // {{{ Type : Key
1027 
1028  enum struct KeyState
1029  { Released = 0
1030  , Pressed = 1
1031  , Repeat = 2
1032  };
1033 
1034  struct Key
1035  {
1036  uint32_t time;
1037  uint32_t code;
1039  };
1040 
1041  static constexpr uint32_t KeyModifier_Alt = 0x00000008;
1042  static constexpr uint32_t KeyModifier_CapsLock = 0x00000002;
1043  static constexpr uint32_t KeyModifier_Control = 0x00000004;
1044  static constexpr uint32_t KeyModifier_Meta = 0x00000040;
1045  static constexpr uint32_t KeyModifier_Shift = 0x00000001;
1046 
1048  {
1049  uint32_t pressed = 0;
1050  uint32_t latched = 0;
1051  uint32_t locked = 0;
1052  uint32_t group = 0;
1053  };
1054 
1055  // }}}
1056  // {{{ Type : Point
1057 
1058  struct PointMm
1059  {
1060  uint32_t time;
1061  float x;
1062  float y;
1063 
1064  friend bool operator==(Yetani::PointMm&, Yetani::PointMm&) noexcept;
1065  };
1066 
1068  {
1069  uint32_t time;
1070  float x;
1071  float y;
1072 
1073  friend bool operator==(Yetani::PointPercent&, Yetani::PointPercent&) noexcept;
1074  };
1075 
1076  struct PointPixel
1077  {
1078  uint32_t time;
1079  int32_t x;
1080  int32_t y;
1081 
1082  friend bool operator==(Yetani::PointPixel&, Yetani::PointPixel&) noexcept;
1083  };
1084 
1085  // }}}
1086  // {{{ Type : Pointer Axis
1087 
1088  enum struct PointerAxisSource
1089  { Unknown
1090  , Continuous
1091  , Finger
1092  , Wheel
1093  , Wheel_Tilt
1094  };
1095 
1096  enum struct PointerAxisType
1097  { Unknown
1098  , Horizontal
1099  , Vertical
1100  };
1101 
1103  {
1104  uint32_t time;
1105  int32_t steps;
1106  float distance;
1109  };
1110 
1111  // }}}
1112  // {{{ Type : Pointer Button
1113 
1115  { Released = 0
1116  , Pressed = 1
1117  };
1118 
1120  {
1121  uint32_t code;
1123  };
1124 
1125  // }}}
1126  // {{{ Type : Size
1127 
1128  struct SizeMm
1129  {
1130  float width;
1131  float height;
1132 
1133  friend bool operator==(Yetani::SizeMm&, Yetani::SizeMm&) noexcept;
1134  };
1135 
1137  {
1138  float width;
1139  float height;
1140 
1141  friend bool operator==(Yetani::SizePercent&, Yetani::SizePercent&) noexcept;
1142  };
1143 
1144  struct SizePixel
1145  {
1146  int32_t width;
1147  int32_t height;
1148 
1149  friend bool operator==(Yetani::SizePixel&, Yetani::SizePixel&) noexcept;
1150  };
1151 
1152  // }}}
1153  // {{{ Connection
1154 
1155  static Yetani* connect() noexcept;
1156  static Yetani* connect(const std::string&) noexcept;
1157  static Yetani* connect(std::error_code&) noexcept;
1158  static Yetani* connect(const std::string&, std::error_code&) noexcept;
1159 
1160  // }}}
1161  // {{{ Cursor
1162 
1164  {
1166  wl_shm_format format = WL_SHM_FORMAT_ARGB8888;
1167  int32_t hotspot_x = 0;
1168  int32_t hotspot_y = 0;
1169  std::chrono::milliseconds time_per_frame = std::chrono::milliseconds(0);
1170  const std::vector<void*>& image_data;
1171  };
1172 
1173  // -------------------------------------------------- //
1174 
1175  std::error_code cursorCreate(const std::string&, const Yetani::CursorConfig&) noexcept;
1176  std::error_code cursorDestroy(const std::string&) noexcept;
1177 
1178  // }}}
1179  // {{{ Keyboard
1180 
1181  int32_t keyRepeatDelay() const noexcept;
1182  int32_t keyRepeatRate() const noexcept;
1183 
1184  // }}}
1185  // {{{ Output : Wayland
1186 
1187  struct Output
1188  {
1189  std::string make = "";
1190  std::string model = "";
1191  int32_t x = 0;
1192  int32_t y = 0;
1193  int32_t width = 0;
1194  int32_t height = 0;
1195  int32_t physical_width_mm = 0;
1196  int32_t physical_height_mm = 0;
1197  int32_t subpixel = 0;
1198  int32_t refresh_mHz = 0;
1199  int32_t scale_factor = 0;
1200  int32_t transform = 0;
1201  uint32_t flags = 0;
1202  float pixels_per_mm_horizontal = 0.0;
1203  float pixels_per_mm_vertical = 0.0;
1204  };
1205 
1206  // -------------------------------------------------- //
1207 
1208  using OutputId = uint32_t;
1209 
1210  using LambdaOutputId = std::function<void(const Yetani::OutputId)>;
1211 
1212  using VectorOutputId = std::vector<OutputId>;
1213 
1214  // -------------------------------------------------- //
1215 
1216  Yetani::Output output(const Yetani::OutputId) const noexcept;
1217  Yetani::VectorOutputId outputVector() const noexcept;
1218  static std::string outputSubpixelName(int32_t) noexcept;
1219  static std::string outputTransformName(int32_t) noexcept;
1220 
1221  Yetani::PointMm outputConvertToMm(const Yetani::OutputId, const Yetani::PointPixel&) const noexcept;
1222  Yetani::PointPercent outputConvertToPercent(const Yetani::OutputId, const Yetani::PointPixel&) const noexcept;
1223  Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointMm&) const noexcept;
1224  Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointPercent&) const noexcept;
1225 
1226  Yetani::SizeMm outputConvertToMm(const Yetani::OutputId, const Yetani::SizePixel&) const noexcept;
1227  Yetani::SizePercent outputConvertToPercent(const Yetani::OutputId, const Yetani::SizePixel&) const noexcept;
1228  Yetani::SizePixel outputConvertToPixel(const Yetani::OutputId, const Yetani::SizeMm&) const noexcept;
1229  Yetani::SizePixel outputConvertToPixel(const Yetani::OutputId, const Yetani::SizePercent&) const noexcept;
1230 
1231  void outputOnAdd(Yetani::LambdaOutputId) noexcept;
1232  void outputOnChange(Yetani::LambdaOutputId) noexcept;
1233  void outputOnRemove(Yetani::LambdaOutputId) noexcept;
1234 
1235  // }}}
1236  // {{{ Output : Xdg
1237 
1238  /* Future
1239  struct XdgOutput
1240  {
1241  std::string xdg_name;
1242  std::string xdg_description;
1243  int32_t xdg_logical_x;
1244  int32_t xdg_logical_y;
1245  int32_t xdg_logical_width;
1246  int32_t xdg_logical_height;
1247  };
1248 
1249  using MapXdgOutputData = std::unordered_map<OutputId, XdgOutput>;
1250 
1251  // -------------------------------------------------- //
1252 
1253  const MapOutputIdXdgOutput& xdgOutputMap() const noexcept;
1254  */
1255 
1256  // }}}
1257  // {{{ Shared Memory
1258 
1259  using VectorShmFormat = std::vector<wl_shm_format>;
1260 
1261  // -------------------------------------------------- //
1262 
1263  const Yetani::VectorShmFormat& shmFormatAvailable() const noexcept;
1264  static uint8_t shmFormatBytesPerPixel(const wl_shm_format) noexcept;
1265  static std::string shmFormatDescription(const wl_shm_format) noexcept;
1266  static std::string shmFormatName(const wl_shm_format) noexcept;
1267 
1268  // }}}
1269  // {{{ Window
1270 
1271  enum struct WindowDecorations
1272  { Client_Side
1273  , Server_Side
1274  };
1275 
1276  enum struct WindowMode
1277  { Normal
1278  , Fullscreen
1279  , Maximized
1280  };
1281 
1282  // -------------------------------------------------- //
1283 
1284  using Lambda = std::function<void()>;
1285  using LambdaKey = std::function<void(const Yetani::Key&, const Yetani::KeyModifier&)>;
1286  using LambdaAxis = std::function<void(const Yetani::PointerAxis&, const Yetani::KeyModifier&)>;
1287  using LambdaButtonMm = std::function<void(const Yetani::PointerButton&, const Yetani::PointMm&, const Yetani::KeyModifier&)>;
1288  using LambdaButtonPercent = std::function<void(const Yetani::PointerButton&, const Yetani::PointPercent&, const Yetani::KeyModifier&)>;
1289  using LambdaButtonPixel = std::function<void(const Yetani::PointerButton&, const Yetani::PointPixel&, const Yetani::KeyModifier&)>;
1290  using LambdaPointMm = std::function<void(const Yetani::PointMm&, const Yetani::KeyModifier&)>;
1291  using LambdaPointPercent = std::function<void(const Yetani::PointPercent&, const Yetani::KeyModifier&)>;
1292  using LambdaPointPixel = std::function<void(const Yetani::PointPixel&, const Yetani::KeyModifier&)>;
1293  using LambdaBool = std::function<void(bool)>;
1295  using LambdaWindowMode = std::function<void(Yetani::WindowMode)>;
1296  using LambdaSizeMm = std::function<void(const Yetani::SizeMm&)>;
1297  using LambdaSizePercent = std::function<void(const Yetani::SizePercent&)>;
1298  using LambdaSizePixel = std::function<void(const Yetani::SizePixel&)>;
1299 
1300  // -------------------------------------------------- //
1301 
1302  class Window
1303  {
1304  public:
1305  Window(void*);
1306  virtual ~Window();
1307 
1308  // {{{ Configuration
1309 
1310  void setClass(const std::string&) noexcept;
1311  void setTitle(const std::string&) noexcept;
1312  std::error_code setDecorations(const Yetani::WindowDecorations) noexcept;
1313  std::error_code setSize(const Yetani::SizeMm&) noexcept;
1314  std::error_code setSize(const Yetani::SizePercent&) noexcept;
1315  std::error_code setSize(const Yetani::SizePixel&) noexcept;
1316  std::error_code setSizeMinMax(const Yetani::SizeMm&, const Yetani::SizeMm&) noexcept;
1317  std::error_code setSizeMinMax(const Yetani::SizePercent&, const Yetani::SizePercent&) noexcept;
1318  std::error_code setSizeMinMax(const Yetani::SizePixel&, const Yetani::SizePixel&) noexcept;
1319 
1320  uint8_t bytesPerPixel() const noexcept;
1321 
1322  // }}}
1323  // {{{ Window Mode
1324 
1325  Yetani::WindowMode windowMode() noexcept;
1326  bool windowModeIs(const Yetani::WindowMode) noexcept;
1327  void windowModeSet(const Yetani::WindowMode) noexcept;
1329 
1330  void minimize() noexcept;
1331 
1332  // }}}
1333  // {{{ Rendering
1334 
1335  std::error_code imageNext(uint8_t*&, Yetani::SizePixel&) noexcept;
1336  void imagePresent() noexcept;
1337  uint32_t time() const noexcept;
1338 
1339  // }}}
1340  // {{{ Conversion
1341 
1342  Yetani::PointMm convertToMm(const Yetani::PointPixel&) const noexcept;
1344  Yetani::PointPixel convertToPixel(const Yetani::PointMm&) const noexcept;
1346 
1347  Yetani::SizeMm convertToMm(const Yetani::SizePixel&) const noexcept;
1349  Yetani::SizePixel convertToPixel(const Yetani::SizeMm&) const noexcept;
1350  Yetani::SizePixel convertToPixel(const Yetani::SizePercent&) const noexcept;
1351 
1352  // }}}
1353  // {{{ Cursor
1354 
1355  std::error_code cursorUse(const std::string&) noexcept;
1356  void cursorHide() noexcept;
1357  void cursorShow() noexcept;
1358 
1359  // }}}
1360  // {{{ Keyboard
1361 
1362  void keyboardOnEnter(Yetani::Lambda) noexcept;
1363  void keyboardOnLeave(Yetani::Lambda) noexcept;
1364  void keyboardOnKey(Yetani::LambdaKey) noexcept;
1365 
1366  // }}}
1367  // {{{ Pointer
1368 
1369  void pointerOnEnter(Yetani::LambdaPointMm) noexcept;
1372  void pointerOnLeave(Yetani::Lambda) noexcept;
1373  void pointerOnMotion(Yetani::LambdaPointMm) noexcept;
1376  void pointerOnButton(Yetani::LambdaButtonMm) noexcept;
1379  void pointerOnAxis(Yetani::LambdaAxis) noexcept;
1380  void pointerOnAxisSource(Yetani::Lambda) noexcept;
1381  void pointerOnAxisStop(Yetani::Lambda) noexcept;
1382  void pointerOnAxisDiscrete(Yetani::Lambda) noexcept;
1383 
1384  // }}}
1385  // {{{ Events
1386 
1387  void onCloseRequest(Yetani::Lambda) noexcept;
1389  void onFocusChange(Yetani::LambdaBool) noexcept;
1390  void onSizeChange(Yetani::LambdaSizeMm) noexcept;
1391  void onSizeChange(Yetani::LambdaSizePercent) noexcept;
1392  void onSizeChange(Yetani::LambdaSizePixel) noexcept;
1393 
1394  // }}}
1395 
1396  struct Memory
1397  {
1400  };
1401 
1402  private:
1403  Yetani* yetani;
1404  struct wl_buffer* wl_buffer;
1405  struct wl_surface* wl_surface;
1406  struct xdg_surface* xdg_surface;
1407  struct xdg_toplevel* xdg_toplevel;
1408  struct zxdg_toplevel_decoration_v1* xdg_decoration;
1409  Yetani::Window::Memory window_memory;
1410  wl_shm_format pixel_format;
1411 
1412  Window(const Window&) = delete;
1413  Window& operator=(const Window&) = delete;
1414  };
1415 
1416  // -------------------------------------------------- //
1417 
1418  static constexpr wl_shm_format SHM_FORMAT_DEFAULT = WL_SHM_FORMAT_XRGB8888;
1419 
1420  // -------------------------------------------------- //
1421 
1422  Yetani::Window* windowCreate(const Yetani::SizeMm&, std::error_code&) noexcept;
1423  Yetani::Window* windowCreate(const Yetani::SizeMm&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1424  Yetani::Window* windowCreate(const Yetani::SizeMm&, const wl_shm_format, std::error_code&) noexcept;
1425  Yetani::Window* windowCreate(const Yetani::SizePercent&, std::error_code&) noexcept;
1426  Yetani::Window* windowCreate(const Yetani::SizePercent&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1427  Yetani::Window* windowCreate(const Yetani::SizePercent&, const wl_shm_format, std::error_code&) noexcept;
1428  Yetani::Window* windowCreate(const Yetani::SizePixel&, std::error_code&) noexcept;
1429  Yetani::Window* windowCreate(const Yetani::SizePixel&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1430  Yetani::Window* windowCreate(const Yetani::SizePixel&, const wl_shm_format, std::error_code&) noexcept;
1431 
1432  // }}}
1433 
1434  private:
1435  static constexpr uint32_t Size_Max = (uint32_t)std::numeric_limits<int32_t>::max();
1436 
1437  Yetani() noexcept;
1438 
1439  // {{{ Type
1440 
1441  using VectorWlSurface = std::vector<struct wl_surface*>;
1442 
1443  // }}}
1444  // {{{ Connection
1445 
1446  void disconnect() noexcept;
1447 
1448  // }}}
1449  // {{{ Cursor
1450 
1451  struct Cursor
1452  {
1453  struct wl_surface* wl_surface = nullptr;
1454  std::vector<::wl_buffer*> buffer_vector = {};
1455  wl_shm_format format = WL_SHM_FORMAT_ARGB8888;
1456  int64_t next_frame_time = 0;
1457  size_t buffer_index = 0;
1458  uint32_t time_per_frame = 0;
1459  int32_t width = 0;
1460  int32_t height = 0;
1461  int32_t hotspot_x = 0;
1462  int32_t hotspot_y = 0;
1463  };
1464 
1465  using MapStringCursor = std::unordered_map<std::string, Yetani::Cursor>;
1466 
1467  MapStringCursor cursor_map;
1468 
1469  // -------------------------------------------------- //
1470 
1471  struct CursorSurface
1472  {
1473  struct wl_pointer* wl_pointer;
1474  struct wl_surface* wl_surface;
1475  uint32_t serial;
1476  int32_t hotspot_x;
1477  int32_t hotspot_y;
1478  bool is_visible;
1479  };
1480 
1481  using MapCursorSurface = std::unordered_map<struct wl_surface*, Yetani::CursorSurface>;
1482 
1483  MapCursorSurface cursor_surface_map;
1484 
1485  // -------------------------------------------------- //
1486 
1487  zakero::MemoryPool cursor_memory_pool;
1488  mutable std::mutex cursor_mutex;
1489  struct wl_shm_pool* cursor_shm_pool;
1490  struct wl_pointer* cursor_pointer;
1491 
1492  // -------------------------------------------------- //
1493 
1494  void cursorAnimate() noexcept;
1495  std::error_code cursorCreateCursor(const std::string&, const Yetani::CursorConfig&) noexcept;
1496  void cursorEnter(struct wl_pointer*, uint32_t, struct wl_surface*) noexcept;
1497  void cursorLeave(struct wl_surface*) noexcept;
1498  void cursorHide(struct wl_surface*) noexcept;
1499  void cursorShow(struct wl_surface*) noexcept;
1500  bool cursorIsHidden(struct wl_surface*) const noexcept;
1501  void cursorSetup() noexcept;
1502  void cursorTeardown() noexcept;
1503  std::error_code cursorAttach(const std::string&, struct wl_surface*) noexcept;
1504  std::error_code cursorDetach(struct wl_surface*) noexcept;
1505 
1506  // }}}
1507  // {{{ Event Loop
1508 
1509  std::jthread event_loop;
1510  std::atomic<bool> event_loop_is_running;
1511 
1512  // -------------------------------------------------- //
1513 
1514  void eventLoopStart() noexcept;
1515  static void eventLoop(std::stop_token, Yetani*) noexcept;
1516 
1517  // }}}
1518  // {{{ Wayland
1519 
1520  struct wl_compositor* compositor;
1521  struct wl_display* display;
1522  struct wl_registry* registry;
1523  struct wl_shm* shm;
1524  Yetani::VectorShmFormat shm_format_vector;
1525 
1526  // }}}
1527  // {{{ Wayland : Seat
1528 
1529  struct Seat
1530  {
1531  struct wl_keyboard* wl_keyboard = nullptr;
1532  struct wl_pointer* wl_pointer = nullptr;
1533  struct wl_touch* wl_touch = nullptr;
1534  std::string name = "";
1535  uint32_t version = 0;
1536  };
1537 
1538  using MapSeat = std::map<struct wl_seat*, Seat>;
1539  using MapIdWlSeat = std::map<uint32_t, struct wl_seat*>;
1540 
1541  Yetani::MapSeat seat_map;
1542  Yetani::MapIdWlSeat id_to_seat;
1543 
1544  // -------------------------------------------------- //
1545 
1546  struct wl_seat* seat;
1547 
1548  // -------------------------------------------------- //
1549 
1550  void seatDestroy(struct wl_seat*&) noexcept;
1551 
1552  // }}}
1553  // {{{ Wayland : Seat : Keyboard
1554 
1555  struct KeyRepeatData
1556  {
1557  std::chrono::time_point<std::chrono::steady_clock> trigger_time = {};
1558  uint32_t base_time = 0;
1559  };
1560 
1561  using KeyRepeatMap = std::map<uint32_t, Yetani::KeyRepeatData>;
1562 
1563  // -------------------------------------------------- //
1564 
1565  struct KeyboardEvent
1566  {
1567  Yetani::Lambda on_enter = {};
1568  Yetani::Lambda on_leave = {};
1569  Yetani::LambdaKey on_key = {};
1570  };
1571 
1572  using MapKeyboardEvent = std::unordered_map<struct wl_surface*, Yetani::KeyboardEvent>;
1573 
1574  // -------------------------------------------------- //
1575 
1576  struct Keyboard
1577  {
1578  struct wl_surface* wl_surface = nullptr;
1579  Yetani::KeyboardEvent* event = nullptr;
1580  Yetani::MapKeyboardEvent event_map = {};
1581  Yetani::KeyModifier modifier = {};
1582  Yetani::KeyRepeatMap repeat_map = {};
1583  char* keymap = nullptr;
1584  uint32_t keymap_size = 0;
1585  int32_t repeat_delay = 0;
1586  int32_t repeat_rate = 0;
1587  };
1588 
1589  Yetani::Keyboard keyboard;
1590 
1591  // -------------------------------------------------- //
1592 
1593  static void keyboardDestroy(Yetani::Keyboard&) noexcept;
1594  static void keyboardRepeat(Yetani::Keyboard&) noexcept;
1595  static void keyboardRepeatAdd(Yetani::Keyboard&, uint32_t, uint32_t) noexcept;
1596  static void keyboardRepeatReleaseAll(Yetani::Keyboard&) noexcept;
1597  static void keyboardRepeatRemove(Yetani::Keyboard&, uint32_t) noexcept;
1598 
1599  // }}}
1600  // {{{ Wayland : Seat : Pointer
1601 
1602  struct PointerEvent
1603  {
1604  Yetani::LambdaAxis on_axis = {};
1605  Yetani::Lambda on_axis_discrete = {};
1606  Yetani::Lambda on_axis_source = {};
1607  Yetani::Lambda on_axis_stop = {};
1608  Yetani::LambdaButtonMm on_button_mm = {};
1609  Yetani::LambdaButtonPercent on_button_percent = {};
1610  Yetani::LambdaButtonPixel on_button_pixel = {};
1611  Yetani::LambdaPointMm on_enter_mm = {};
1612  Yetani::LambdaPointPercent on_enter_percent = {};
1613  Yetani::LambdaPointPixel on_enter_pixel = {};
1614  Yetani::Lambda on_leave = {};
1615  Yetani::LambdaPointMm on_motion_mm = {};
1616  Yetani::LambdaPointPercent on_motion_percent = {};
1617  Yetani::LambdaPointPixel on_motion_pixel = {};
1618  };
1619 
1620  using MapPointerEvent = std::unordered_map<struct wl_surface*, Yetani::PointerEvent>;
1621 
1622  // -------------------------------------------------- //
1623 
1624  struct Pointer
1625  {
1626  // --- Common --- //
1627  Yetani* yetani = nullptr;
1628  struct wl_surface* wl_surface = nullptr;
1629  struct wl_pointer* wl_pointer = nullptr;
1630  Yetani::PointerEvent* event = nullptr;
1631  Yetani::MapPointerEvent event_map = {};
1632 
1633  // --- Processed Data --- //
1634  Yetani::PointMm point_mm = {};
1635  Yetani::PointPercent point_percent = {};
1636  Yetani::PointPixel point_pixel = {};
1637 
1638  // --- Axis --- //
1639  Yetani::PointerAxis axis = {};
1640 
1641  // --- Button --- //
1642  Yetani::PointerButton button = {};
1643  uint32_t button_event_code = 0;
1644  bool button_is_pressed = false;
1645  uint32_t button_time = {};
1646 
1647  // --- Enter --- //
1648  struct wl_surface* enter_surface = nullptr;
1649  Yetani::PointPixel enter_point = {};
1650  uint32_t enter_serial = 0;
1651 
1652  // --- Leave --- //
1653  struct wl_surface* leave_surface = nullptr;
1654 
1655  // --- Motion --- //
1656  Yetani::PointPixel motion_point = {};
1657  };
1658 
1659  Yetani::Pointer pointer;
1660 
1661  // -------------------------------------------------- //
1662 
1663  static void pointerClear(struct Pointer&) noexcept;
1664 
1665  // }}}
1666  // {{{ Wayland : Output
1667 
1668  enum struct OutputState
1669  { Done
1670  , Added
1671  , Changed
1672  };
1673 
1674  // -------------------------------------------------- //
1675 
1676  using VectorWlOutput = std::vector<struct wl_output*>;
1677 
1678  using MapWlOutputOutputState = std::unordered_map<struct wl_output*, Yetani::OutputState>;
1679  using MapOutputIdWlOutput = std::unordered_map<Yetani::OutputId, struct wl_output*>;
1680  using MapWlOutputOutputId = std::unordered_map<struct wl_output*, Yetani::OutputId>;
1681  using MapWlSurfaceVectorWlOutput = std::unordered_map<struct wl_surface*, Yetani::VectorWlOutput>;
1682  using MapWlOutputOutput = std::unordered_map<struct wl_output*, Output>;
1683 
1684  // -------------------------------------------------- //
1685 
1686  struct OutputData
1687  {
1688  Yetani::MapWlSurfaceVectorWlOutput surface_output_map = {};
1689  Yetani::MapOutputIdWlOutput outputid_to_wloutput = {};
1690  Yetani::MapWlOutputOutput output_map = {};
1691  Yetani::MapWlOutputOutputId wloutput_to_outputid = {};
1692  mutable std::mutex mutex = {};
1693  };
1694 
1695  Yetani::OutputData output_data;
1696 
1697  // -------------------------------------------------- //
1698 
1699  Yetani::LambdaOutputId on_output_add;
1700  Yetani::LambdaOutputId on_output_change;
1701  Yetani::LambdaOutputId on_output_remove;
1702 
1703  Yetani::MapWlOutputOutput output_changes_map;
1704  Yetani::MapWlOutputOutputState output_state_map;
1705 
1706  Yetani::VectorWlSurface output_notify_surface_vector;
1707 
1708  // -------------------------------------------------- //
1709 
1710  void convertPixel(struct wl_surface*, const int32_t, const int32_t, float&, float&, float&, float&) const noexcept;
1711 
1712  std::pair<float, float> convertPixelToMm(const Yetani::Output&, int32_t, int32_t) const noexcept;
1713  std::pair<float, float> convertPixelToPercent(const Yetani::Output&, int32_t, int32_t) const noexcept;
1714  std::pair<int32_t, int32_t> convertMmToPixel(const Yetani::Output&, float, float) const noexcept;
1715  std::pair<int32_t, int32_t> convertPercentToPixel(const Yetani::Output&, float, float) const noexcept;
1716 
1717  static void outputNotifySurface(Yetani*, struct wl_output*, struct wl_surface*) noexcept;
1718 
1719  // }}}
1720  // {{{ Wayland : Buffer
1721 
1722  struct SurfaceSize;
1723 
1724  struct BufferData
1725  {
1726  MemoryPool* memory_pool = nullptr;
1727  off_t offset = 0;
1728  };
1729 
1730  using MapBufferData = std::unordered_map<struct wl_buffer*, BufferData>;
1731 
1732  // -------------------------------------------------- //
1733 
1734  struct Buffer
1735  {
1736  MapBufferData map = {};
1737  std::mutex mutex = {};
1738  };
1739 
1740  Buffer buffer;
1741 
1742  // -------------------------------------------------- //
1743 
1744  static wl_buffer* bufferCreate(Yetani::SurfaceSize&, Yetani::Window::Memory*, Yetani::Buffer*) noexcept;
1745  static wl_buffer* bufferCreateAndRelease(Yetani*, Yetani::SurfaceSize&, Yetani::Window::Memory*) noexcept;
1746  static void bufferDestroy(struct wl_buffer*&) noexcept;
1747 
1748  // }}}
1749  // {{{ Wayland : Surface
1750 
1751  struct SurfaceEvent
1752  {
1753  Yetani::LambdaSizeMm on_size_mm_change = {};
1754  Yetani::LambdaSizePercent on_size_percent_change = {};
1755  Yetani::LambdaSizePixel on_size_pixel_change = {};
1756  };
1757 
1758  using MapSurfaceEvent = std::map<struct wl_surface*, Yetani::SurfaceEvent>;
1759 
1760  MapSurfaceEvent surface_event_map;
1761 
1762  // -------------------------------------------------- //
1763 
1764  enum struct SizeUnit
1765  { Millimeter
1766  , Percent
1767  , Pixel
1768  };
1769 
1770  // This is the data that needs to be locked from resizing
1771  // Use mainly by XdgSurface related methods
1772  struct SurfaceExtent
1773  {
1774  Yetani::SizeUnit preferred_unit = {};
1775  Yetani::SizeMm preferred_mm = {};
1776  Yetani::SizePercent preferred_percent = {};
1777  Yetani::SizeMm size_mm = {};
1778  Yetani::SizePercent size_percent = {};
1779  Yetani::SizePixel size_pixel = {};
1780  Yetani::SizePixel size_pixel_max = {};
1781  Yetani::SizePixel size_pixel_min = {};
1782  };
1783 
1784  using MapSurfaceExtent = std::unordered_map<struct wl_surface*, Yetani::SurfaceExtent>;
1785 
1786  MapSurfaceExtent surface_extent_map;
1787  std::mutex surface_extent_mutex; // For surface adding and removing
1788 
1789  // -------------------------------------------------- //
1790 
1791  struct SurfaceFrame
1792  {
1793  struct wl_callback* callback = nullptr;
1794  struct wl_surface* wl_surface = nullptr;
1795  std::atomic<wl_buffer*> buffer_next = {};
1796  uint32_t width = 0;
1797  uint32_t height = 0;
1798  uint32_t time_ms = 0;
1799  };
1800 
1801  using MapSurfaceFrame = std::unordered_map<struct wl_surface*, Yetani::SurfaceFrame>;
1802 
1803  MapSurfaceFrame surface_frame_map;
1804 
1805  // -------------------------------------------------- //
1806 
1807  struct SurfaceSize
1808  {
1809  int32_t width;
1810  int32_t height;
1811  int32_t stride;
1812  uint32_t in_bytes;
1813  wl_shm_format pixel_format;
1814  uint8_t bytes_per_pixel;
1815  };
1816 
1817  using MapSurfaceSize = std::unordered_map<struct wl_surface*, Yetani::SurfaceSize>;
1818 
1819  MapSurfaceSize surface_size_map;
1820 
1821  // -------------------------------------------------- //
1822 
1823  using MapSurfaceResizeMutex = std::unordered_map<struct wl_surface*, std::mutex>;
1824 
1825  MapSurfaceResizeMutex surface_resize_mutex_map;
1826 
1827  // -------------------------------------------------- //
1828 
1829  static void surfaceCalculateSize(Yetani*, struct wl_surface*, const Yetani::SizePixel&) noexcept;
1830  static struct wl_surface* surfaceCreate(Yetani*, const wl_shm_format, const Yetani::SizePixel&, const bool, Yetani::Window::Memory&) noexcept;
1831  static void surfaceDestroy(Yetani*, struct wl_surface*&) noexcept;
1832 
1833  // }}}
1834  // {{{ Window
1835 
1836  struct WindowData
1837  {
1838  Yetani* yetani;
1839  struct wl_shm* wl_shm;
1840  struct wl_output* wl_output;
1841  std::string file_name;
1842  Yetani::SizeMm size_mm;
1843  Yetani::SizePercent size_percent;
1844  Yetani::SizePixel size_pixel;
1845  Yetani::SizeUnit size_unit;
1846  wl_shm_format pixel_format;
1847  std::error_code error;
1848  };
1849 
1850  // -------------------------------------------------- //
1851 
1852  Yetani::Window* windowCreate(const Yetani::SizeUnit, const Yetani::SizeMm&, const Yetani::SizePercent&, const Yetani::SizePixel&, const wl_shm_format, std::error_code&) noexcept;
1853  void windowDataInit(Yetani::WindowData&) noexcept;
1854  void windowDataInitOutput(Yetani::WindowData&) noexcept;
1855  void windowInitMemory(Yetani::WindowData&, Yetani::Window::Memory&) noexcept;
1856  void windowInitOutput(Yetani::WindowData&, struct wl_surface*) noexcept;
1857  void windowEraseMemory(Yetani::Window::Memory&) noexcept;
1858  void windowEraseOutput(struct wl_surface*) noexcept;
1859  void windowEraseSurfaceExtent(struct wl_surface*) noexcept;
1860 
1861  // }}}
1862  // {{{ Utility
1863 
1864  std::vector<Yetani::Window*> window_vector;
1865  std::mutex window_vector_mutex;
1866 
1867  // -------------------------------------------------- //
1868 
1869  void windowAdd(Yetani::Window*) noexcept;
1870  void windowRemove(Yetani::Window*) noexcept;
1871 
1872  // }}}
1873  // {{{ XDG
1874 
1875  enum XdgState : int32_t
1876  { Unknown = 0
1877  , Toplevel_Active = 1
1878  , Toplevel_Attach_Buffer = 2
1879  , Toplevel_Resizing = 3
1880  , Toplevel_Window_Fullscreen = 4
1881  , Toplevel_Window_Maximized = 5
1882  , Toplevel_Window_Normal = 6
1883  , Toplevel_Decoration = 7
1884  };
1885 
1886  using VectorXdgStateChange = std::vector<int32_t>;
1887  using MapXdgStateChange = std::unordered_map<struct xdg_surface*, Yetani::VectorXdgStateChange>;
1888 
1889  Yetani::MapXdgStateChange xdg_state_change_map;
1890  std::mutex xdg_state_change_mutex;
1891 
1892  // -------------------------------------------------- //
1893 
1894  struct xdg_wm_base* xdg_wm_base;
1895 
1896  // -------------------------------------------------- //
1897 
1898  static Yetani::WindowMode toWindowMode(const Yetani::XdgState) noexcept;
1899  static Yetani::XdgState toXdgState(const Yetani::WindowMode) noexcept;
1900 
1901  // }}}
1902  // {{{ XDG : Surface
1903 
1904  struct XdgSurface
1905  {
1906  Yetani* yetani = nullptr;
1907  struct wl_surface* wl_surface = nullptr;
1908  };
1909 
1910  using MapXdgSurface = std::unordered_map<struct wl_surface*, Yetani::XdgSurface>;
1911 
1912  Yetani::MapXdgSurface xdg_surface_map;
1913 
1914  // -------------------------------------------------- //
1915 
1916  struct xdg_surface* xdgSurfaceCreate(struct wl_surface*) noexcept;
1917  void xdgSurfaceDestroy(struct wl_surface*, struct xdg_surface*&) noexcept;
1918  void xdgSurfaceSetExtent(struct wl_surface*, const Yetani::SizeUnit&, const Yetani::SizeMm&, const Yetani::SizePercent&, const Yetani::SizePixel&) noexcept;
1919 
1920  // }}}
1921  // {{{ XDG : Toplevel
1922 
1923  struct XdgToplevel
1924  {
1925  Yetani::VectorXdgStateChange* state_change = nullptr;
1926  Yetani::Lambda close_request_lambda = {};
1927  Yetani::LambdaBool is_active_lambda = {};
1928  bool is_active = false;
1929  Yetani::XdgState window_state = XdgState::Unknown;
1930  Yetani::LambdaWindowMode window_state_lambda = {};
1931  Yetani::SizePixel previous_size = {};
1932  struct xdg_toplevel* xdg_toplevel = nullptr;
1933  };
1934 
1935  using MapXdgToplevel = std::unordered_map<struct xdg_surface*, Yetani::XdgToplevel>;
1936 
1937  MapXdgToplevel xdg_toplevel_map;
1938 
1939  // -------------------------------------------------- //
1940 
1941  struct xdg_toplevel* xdgToplevelCreate(struct xdg_surface*) noexcept;
1942  void xdgToplevelDestroy(struct xdg_surface*, struct xdg_toplevel*&) noexcept;
1943  static void xdgToplevelSizeChange(Yetani*, struct wl_surface*, const Yetani::SizePixel&) noexcept;
1944  static void xdgToplevelSizeMinMaxChange(Yetani*, struct xdg_toplevel*, struct wl_surface*, const Yetani::SizePixel&, const Yetani::SizePixel&) noexcept;
1945  static void xdgToplevelWindowChange(Yetani*, struct wl_surface*, Yetani::XdgToplevel&, const Yetani::XdgState, const Yetani::SizePixel&) noexcept;
1946 
1947  // }}}
1948  // {{{ XDG : Decoration Manager (Unstable)
1949 
1950  struct XdgDecoration
1951  {
1952  Yetani::VectorXdgStateChange* state_change = nullptr;
1953  Yetani::LambdaWindowDecorations lambda = {};
1954  uint32_t state = 0;
1955  bool is_present = false;
1956  //struct zxdg_toplevel_decoration_v1* xdg_decoration;
1957  };
1958 
1959  using MapXdgDecoration = std::unordered_map<struct xdg_surface*, Yetani::XdgDecoration>;
1960 
1961  MapXdgDecoration xdg_decoration_map;
1962 
1963  // -------------------------------------------------- //
1964 
1965  struct zxdg_decoration_manager_v1* decoration_manager;
1966 
1967  // -------------------------------------------------- //
1968 
1969  struct zxdg_toplevel_decoration_v1* xdgDecorationCreate(struct xdg_surface*, struct xdg_toplevel*) noexcept;
1970  void xdgDecorationDestroy(struct xdg_surface*, struct xdg_toplevel*, struct zxdg_toplevel_decoration_v1*&) noexcept;
1971  static void xdgDecorationChange(Yetani::XdgDecoration&, const uint32_t) noexcept;
1972 
1973  // }}}
1974  // {{{ Listener Handlers : Wayland
1975 
1976  static struct wl_buffer_listener buffer_listener;
1977  static struct wl_callback_listener frame_callback_listener;
1978  static struct wl_keyboard_listener keyboard_listener;
1979  static struct wl_output_listener output_listener;
1980  static struct wl_pointer_listener pointer_listener;
1981  static struct wl_registry_listener registry_listener;
1982  static struct wl_seat_listener seat_listener;
1983  static struct wl_shm_listener shm_listener;
1984  static struct wl_surface_listener surface_listener;
1985 
1986  // -------------------------------------------------- //
1987 
1988  static void handlerBufferRelease(void*, struct wl_buffer*) noexcept;
1989 
1990  static void handlerKeyboardEnter(void*, struct wl_keyboard*, uint32_t, struct wl_surface*, struct wl_array*) noexcept;
1991  static void handlerKeyboardKey(void*, struct wl_keyboard*, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
1992  static void handlerKeyboardKeymap(void*, struct wl_keyboard*, uint32_t, int32_t, uint32_t) noexcept;
1993  static void handlerKeyboardLeave(void*, struct wl_keyboard*, uint32_t, struct wl_surface*) noexcept;
1994  static void handlerKeyboardModifiers(void*, struct wl_keyboard*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
1995  static void handlerKeyboardRepeatInfo(void*, struct wl_keyboard*, int32_t, int32_t) noexcept;
1996 
1997  static void handlerOutputDone(void*, struct wl_output*) noexcept;
1998  static void handlerOutputGeometry(void*, struct wl_output*, int32_t, int32_t, int32_t, int32_t, int32_t, const char*, const char*, int32_t) noexcept;
1999  static void handlerOutputMode(void*, struct wl_output*, uint32_t, int32_t, int32_t, int32_t) noexcept;
2000  static void handlerOutputScale(void*, struct wl_output*, int32_t) noexcept;
2001  static void handlerPointerAxis(void*, struct wl_pointer*, uint32_t, uint32_t, wl_fixed_t) noexcept;
2002  static void handlerPointerAxisDiscrete(void*, struct wl_pointer*, uint32_t, int32_t) noexcept;
2003  static void handlerPointerAxisSource(void*, struct wl_pointer*, uint32_t) noexcept;
2004  static void handlerPointerAxisStop(void*, struct wl_pointer*, uint32_t, uint32_t) noexcept;
2005  static void handlerPointerButton(void*, struct wl_pointer*, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
2006  static void handlerPointerEnter(void*, struct wl_pointer*, uint32_t, struct wl_surface*, wl_fixed_t, wl_fixed_t) noexcept;
2007  static void handlerPointerFrame(void*, struct wl_pointer*) noexcept;
2008  static void handlerPointerLeave(void*, struct wl_pointer*, uint32_t, struct wl_surface*) noexcept;
2009  static void handlerPointerMotion(void*, struct wl_pointer*, uint32_t, wl_fixed_t, wl_fixed_t) noexcept;
2010  static void handlerRegistryGlobal(void*, struct wl_registry*, uint32_t, const char*, uint32_t) noexcept;
2011  static void handlerRegistryRemove(void*, struct wl_registry*, uint32_t) noexcept;
2012  static void handlerSeatCapabilities(void*, struct wl_seat*, uint32_t) noexcept;
2013  static void handlerSeatName(void*, struct wl_seat*, const char*) noexcept;
2014  static void handlerShmFormat(void*, struct wl_shm*, uint32_t) noexcept;
2015  static void handlerSurfaceEnter(void*, struct wl_surface*, struct wl_output*) noexcept;
2016  static void handlerSurfaceLeave(void*, struct wl_surface*, struct wl_output*) noexcept;
2017  static void handlerSwapBuffers(void*, struct wl_callback*, uint32_t) noexcept;
2018 
2019  // }}}
2020  // {{{ Listener Handlers : Wayland Unstable
2021  // }}}
2022  // {{{ Listener Handlers : XDG
2023 
2024  static struct xdg_wm_base_listener xdg_wm_base_listener;
2025  static struct xdg_surface_listener xdg_surface_listener;
2026  static struct xdg_toplevel_listener xdg_toplevel_listener;
2027 
2028  // -------------------------------------------------- //
2029 
2030  static void handlerXdgSurfaceConfigure(void*, struct xdg_surface*, uint32_t) noexcept;
2031  static void handlerXdgToplevelClose(void*, struct xdg_toplevel*) noexcept;
2032  static void handlerXdgToplevelConfigure(void*, struct xdg_toplevel*, int32_t, int32_t, struct wl_array*) noexcept;
2033  static void handlerXdgWmBasePing(void*, struct xdg_wm_base*, uint32_t) noexcept;
2034 
2035  // }}}
2036  // {{{ Listener Handlers : XDG Unstable
2037 
2038  static struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener;
2039 
2040  // -------------------------------------------------- //
2041 
2042  static void handlerXdgToplevelDecorationConfigure(void*, struct zxdg_toplevel_decoration_v1*, uint32_t mode) noexcept;
2043 
2044  // }}}
2045 
2046  Yetani(const Yetani&) = delete;
2047  Yetani& operator=(const Yetani&) = delete;
2048  }; // class Yetani
2049 
2050  // }}}
2051  // {{{ Convenience
2052 
2053  std::string to_string(const wl_shm_format) noexcept;
2054  std::string to_string(const std::error_code&) noexcept;
2055  std::string to_string(const Yetani::KeyModifier&) noexcept;
2056  std::string to_string(const Yetani::KeyState) noexcept;
2057  std::string to_string(const Yetani::Output&) noexcept;
2058  std::string to_string(const Yetani::PointerAxisSource) noexcept;
2059  std::string to_string(const Yetani::PointerAxisType) noexcept;
2060  std::string to_string(const Yetani::PointerButtonState) noexcept;
2061  std::string to_string(const Yetani::WindowMode) noexcept;
2062 
2063  // }}}
2064 }
2065 
2066 // {{{ Implementation
2067 
2068 #ifdef ZAKERO_YETANI_IMPLEMENTATION
2069 
2070 // {{{ Macros
2071 
2072 // {{{ Macros : Doxygen
2073 
2074 #ifdef ZAKERO__DOXYGEN_DEFINE_DOCS
2075 
2076 // Only used for generating Doxygen documentation
2077 
2089 #define ZAKERO_YETANI_IMPLEMENTATION
2090 
2099 #define ZAKERO_YETANI_ENABLE_DEBUG
2100 
2109 #define ZAKERO_YETANI_ENABLE_SAFE_MODE
2110 
2111 #endif // ZAKERO__DOXYGEN_DEFINE_DOCS
2112 
2113 // }}}
2114 
2130 #ifdef ZAKERO_YETANI_ENABLE_DEBUG
2131 #define ZAKERO_YETANI__DEBUG_DISABLED false
2132 #else
2133 #define ZAKERO_YETANI__DEBUG_DISABLED true
2134 #endif
2135 
2136 
2149 #ifndef ZAKERO_YETANI_ENABLE_DEBUG_STREAM
2150 #define ZAKERO_YETANI_ENABLE_DEBUG_STREAM std::cerr
2151 #endif
2152 
2153 
2171 #define ZAKERO_YETANI__DEBUG \
2172  if(ZAKERO_YETANI__DEBUG_DISABLED) {} \
2173  else ZAKERO_YETANI_ENABLE_DEBUG_STREAM \
2174  << __FILE__"(" \
2175  << std::to_string(__LINE__) \
2176  << ") " \
2177  << __PRETTY_FUNCTION__ \
2178  << " "
2179 
2196 #define ZAKERO_YETANI__DEBUG_VAR(var_) \
2197  ZAKERO_YETANI__DEBUG \
2198  << #var_ << ": " << var_ \
2199  << "\n";
2200 
2216 #define ZAKERO_YETANI__DEBUG_BOOL(var_) \
2217  ZAKERO_YETANI__DEBUG \
2218  << #var_ << ": " << std::boolalpha << var_ \
2219  << "\n";
2220 
2231 #define ZAKERO_YETANI__ERROR(err_) std::error_code(err_, YetaniErrorCategory)
2232 
2233 
2250 #define ZAKERO_YETANI__SHM_FORMAT \
2251  X(WL_SHM_FORMAT_ARGB8888 , 4 , "32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian" ) \
2252  X(WL_SHM_FORMAT_XRGB8888 , 4 , "32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian" ) \
2253  X(WL_SHM_FORMAT_C8 , 1 , "8-bit color index format, [7:0] C" ) \
2254  X(WL_SHM_FORMAT_RGB332 , 1 , "8-bit RGB format, [7:0] R:G:B 3:3:2" ) \
2255  X(WL_SHM_FORMAT_BGR233 , 1 , "8-bit BGR format, [7:0] B:G:R 2:3:3" ) \
2256  X(WL_SHM_FORMAT_XRGB4444 , 2 , "16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian" ) \
2257  X(WL_SHM_FORMAT_XBGR4444 , 2 , "16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian" ) \
2258  X(WL_SHM_FORMAT_RGBX4444 , 2 , "16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian" ) \
2259  X(WL_SHM_FORMAT_BGRX4444 , 2 , "16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian" ) \
2260  X(WL_SHM_FORMAT_ARGB4444 , 2 , "16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian" ) \
2261  X(WL_SHM_FORMAT_ABGR4444 , 2 , "16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian" ) \
2262  X(WL_SHM_FORMAT_RGBA4444 , 2 , "16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian" ) \
2263  X(WL_SHM_FORMAT_BGRA4444 , 2 , "16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian" ) \
2264  X(WL_SHM_FORMAT_XRGB1555 , 2 , "16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian" ) \
2265  X(WL_SHM_FORMAT_XBGR1555 , 2 , "16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian" ) \
2266  X(WL_SHM_FORMAT_RGBX5551 , 2 , "16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian" ) \
2267  X(WL_SHM_FORMAT_BGRX5551 , 2 , "16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian" ) \
2268  X(WL_SHM_FORMAT_ARGB1555 , 2 , "16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian" ) \
2269  X(WL_SHM_FORMAT_ABGR1555 , 2 , "16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian" ) \
2270  X(WL_SHM_FORMAT_RGBA5551 , 2 , "16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian" ) \
2271  X(WL_SHM_FORMAT_BGRA5551 , 2 , "16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian" ) \
2272  X(WL_SHM_FORMAT_RGB565 , 2 , "16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian" ) \
2273  X(WL_SHM_FORMAT_BGR565 , 2 , "16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian" ) \
2274  X(WL_SHM_FORMAT_RGB888 , 3 , "24-bit RGB format, [23:0] R:G:B little endian" ) \
2275  X(WL_SHM_FORMAT_BGR888 , 3 , "24-bit BGR format, [23:0] B:G:R little endian" ) \
2276  X(WL_SHM_FORMAT_XBGR8888 , 4 , "32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian" ) \
2277  X(WL_SHM_FORMAT_RGBX8888 , 4 , "32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian" ) \
2278  X(WL_SHM_FORMAT_BGRX8888 , 4 , "32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian" ) \
2279  X(WL_SHM_FORMAT_ABGR8888 , 4 , "32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian" ) \
2280  X(WL_SHM_FORMAT_RGBA8888 , 4 , "32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian" ) \
2281  X(WL_SHM_FORMAT_BGRA8888 , 4 , "32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian" ) \
2282  X(WL_SHM_FORMAT_XRGB2101010 , 4 , "32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian" ) \
2283  X(WL_SHM_FORMAT_XBGR2101010 , 4 , "32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian" ) \
2284  X(WL_SHM_FORMAT_RGBX1010102 , 4 , "32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian" ) \
2285  X(WL_SHM_FORMAT_BGRX1010102 , 4 , "32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian" ) \
2286  X(WL_SHM_FORMAT_ARGB2101010 , 4 , "32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian" ) \
2287  X(WL_SHM_FORMAT_ABGR2101010 , 4 , "32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian" ) \
2288  X(WL_SHM_FORMAT_RGBA1010102 , 4 , "32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian" ) \
2289  X(WL_SHM_FORMAT_BGRA1010102 , 4 , "32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian" ) \
2290  X(WL_SHM_FORMAT_YUYV , 4 , "packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian" ) \
2291  X(WL_SHM_FORMAT_YVYU , 4 , "packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian" ) \
2292  X(WL_SHM_FORMAT_UYVY , 4 , "packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian" ) \
2293  X(WL_SHM_FORMAT_VYUY , 4 , "packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian" ) \
2294  X(WL_SHM_FORMAT_AYUV , 4 , "packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian" ) \
2295  X(WL_SHM_FORMAT_NV12 , 8 , "2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane" ) \
2296  X(WL_SHM_FORMAT_NV21 , 8 , "2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane" ) \
2297  X(WL_SHM_FORMAT_NV16 , 8 , "2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane" ) \
2298  X(WL_SHM_FORMAT_NV61 , 8 , "2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane" ) \
2299  X(WL_SHM_FORMAT_YUV410 , 8 , "3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes" ) \
2300  X(WL_SHM_FORMAT_YVU410 , 8 , "3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes" ) \
2301  X(WL_SHM_FORMAT_YUV411 , 8 , "3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes" ) \
2302  X(WL_SHM_FORMAT_YVU411 , 8 , "3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes" ) \
2303  X(WL_SHM_FORMAT_YUV420 , 8 , "3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes" ) \
2304  X(WL_SHM_FORMAT_YVU420 , 8 , "3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes" ) \
2305  X(WL_SHM_FORMAT_YUV422 , 8 , "3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes" ) \
2306  X(WL_SHM_FORMAT_YVU422 , 8 , "3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes" ) \
2307  X(WL_SHM_FORMAT_YUV444 , 8 , "3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes" ) \
2308  X(WL_SHM_FORMAT_YVU444 , 8 , "3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes" ) \
2309  X(WL_SHM_FORMAT_R8 , 1 , "[7:0] R" ) \
2310  X(WL_SHM_FORMAT_R16 , 2 , "[15:0] R little endian" ) \
2311  X(WL_SHM_FORMAT_RG88 , 2 , "[15:0] R:G 8:8 little endian" ) \
2312  X(WL_SHM_FORMAT_GR88 , 2 , "[15:0] G:R 8:8 little endian" ) \
2313  X(WL_SHM_FORMAT_RG1616 , 4 , "[31:0] R:G 16:16 little endian" ) \
2314  X(WL_SHM_FORMAT_GR1616 , 4 , "[31:0] G:R 16:16 little endian" ) \
2315  X(WL_SHM_FORMAT_XRGB16161616F , 8 , "[63:0] x:R:G:B 16:16:16:16 little endian" ) \
2316  X(WL_SHM_FORMAT_XBGR16161616F , 8 , "[63:0] x:B:G:R 16:16:16:16 little endian" ) \
2317  X(WL_SHM_FORMAT_ARGB16161616F , 8 , "[63:0] A:R:G:B 16:16:16:16 little endian" ) \
2318  X(WL_SHM_FORMAT_ABGR16161616F , 8 , "[63:0] A:B:G:R 16:16:16:16 little endian" ) \
2319  X(WL_SHM_FORMAT_XYUV8888 , 4 , "[31:0] X:Y:Cb:Cr 8:8:8:8 little endian" ) \
2320  X(WL_SHM_FORMAT_VUY888 , 3 , "[23:0] Cr:Cb:Y 8:8:8 little endian" ) \
2321  X(WL_SHM_FORMAT_VUY101010 , 4 , "Y followed by U then V, 10:10:10. Non-linear modifier only" ) \
2322  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" ) \
2323  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" ) \
2324  X(WL_SHM_FORMAT_Y216 , 8 , "[63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels" ) \
2325  X(WL_SHM_FORMAT_Y410 , 4 , "[31:0] A:Cr:Y:Cb 2:10:10:10 little endian" ) \
2326  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" ) \
2327  X(WL_SHM_FORMAT_Y416 , 8 , "[63:0] A:Cr:Y:Cb 16:16:16:16 little endian" ) \
2328  X(WL_SHM_FORMAT_XVYU2101010 , 4 , "[31:0] X:Cr:Y:Cb 2:10:10:10 little endian" ) \
2329  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" ) \
2330  X(WL_SHM_FORMAT_XVYU16161616 , 8 , "[63:0] X:Cr:Y:Cb 16:16:16:16 little endian" ) \
2331  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" ) \
2332  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" ) \
2333  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" ) \
2334  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" ) \
2335  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" ) \
2336  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" ) \
2337  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" ) \
2338  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" ) \
2339  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" ) \
2340  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" ) \
2341  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" ) \
2342  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" ) \
2343  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" ) \
2344  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" ) \
2345  X(WL_SHM_FORMAT_NV24 , 0 , "[UNKNOWN SIZE] non-subsampled Cr:Cb plane" ) \
2346  X(WL_SHM_FORMAT_NV42 , 0 , "[UNKNOWN SIZE] non-subsampled Cb:Cr plane" ) \
2347  X(WL_SHM_FORMAT_P210 , 0 , "[UNKNOWN SIZE] 2x1 subsampled Cr:Cb plane, 10 bits per channel" ) \
2348  X(WL_SHM_FORMAT_P010 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 10 bits per channel" ) \
2349  X(WL_SHM_FORMAT_P012 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 12 bits per channel" ) \
2350  X(WL_SHM_FORMAT_P016 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 16 bits per channel" ) \
2351 
2352 
2358 #define ZAKERO_YETANI__OUTPUT_SUBPIXEL \
2359  X(WL_OUTPUT_SUBPIXEL_UNKNOWN , "Unkown Geometry" ) \
2360  X(WL_OUTPUT_SUBPIXEL_NONE , "No Geometry" ) \
2361  X(WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB , "Horizontal RGB" ) \
2362  X(WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR , "Horizontal BGR" ) \
2363  X(WL_OUTPUT_SUBPIXEL_VERTICAL_RGB , "Vertical RGB" ) \
2364  X(WL_OUTPUT_SUBPIXEL_VERTICAL_BGR , "Vertical BGR" ) \
2365 
2366 
2372 #define ZAKERO_YETANI__OUTPUT_TRANSFORM \
2373  X(WL_OUTPUT_TRANSFORM_NORMAL , "No Transform" ) \
2374  X(WL_OUTPUT_TRANSFORM_90 , "90 degrees Counter-Clockwise" ) \
2375  X(WL_OUTPUT_TRANSFORM_180 , "180 degrees Counter-Clockwise" ) \
2376  X(WL_OUTPUT_TRANSFORM_270 , "270 degrees Counter-Clockwise" ) \
2377  X(WL_OUTPUT_TRANSFORM_FLIPPED , "180 degree flip around a vertical axis" ) \
2378  X(WL_OUTPUT_TRANSFORM_FLIPPED_90 , "Flig and rotate 90 degrees counter-clockwise" ) \
2379  X(WL_OUTPUT_TRANSFORM_FLIPPED_180 , "Flig and rotate 180 degrees counter-clockwise" ) \
2380 
2381 
2405 #define ZAKERO_YETANI__ARRAY_FOR_EACH(type_, pos_, array_) \
2406  for(type_ pos_ = (type_)(array_)->data \
2407  ; (const char*)pos_ < ((const char*)(array_)->data + (array_)->size) \
2408  ; (pos_)++ \
2409  )
2410 
2411 // }}}
2412 
2413 namespace zakero
2414 {
2415 // {{{ Anonymous Namespace
2416 
2417 namespace
2418 {
2419  // {{{ Cursor Names (Not used yet)
2420  /*
2421  * \brief Common cursor names
2422  *
2423  * These were found in:
2424  * - gdkcursor-wayland.c
2425  * - /usr/share/icons/whiteglass/cursors
2426  const std::array<const char*, 131> common_cursor_names =
2427  { "X_cursor"
2428  , "alias"
2429  , "all-scroll"
2430  , "arrow"
2431  , "base_arrow_down"
2432  , "base_arrow_up"
2433  , "bd_double_arrow"
2434  , "boat"
2435  , "bottom_left_corner"
2436  , "bottom_right_corner"
2437  , "bottom_side"
2438  , "bottom_tee"
2439  , "cell"
2440  , "center_ptr"
2441  , "circle"
2442  , "closedhand"
2443  , "col-resize"
2444  , "color-picker"
2445  , "context-menu"
2446  , "copy"
2447  , "cross"
2448  , "cross_reverse"
2449  , "crossed_circle"
2450  , "crosshair"
2451  , "default"
2452  , "dnd-copy"
2453  , "dnd-link"
2454  , "dnd-move"
2455  , "dnd-no-drop"
2456  , "dnd-none"
2457  , "dot"
2458  , "dot_box_mask"
2459  , "double_arrow"
2460  , "down-arrow"
2461  , "draft"
2462  , "draft_large"
2463  , "draft_small"
2464  , "draped_box"
2465  , "e-resize"
2466  , "ew-resize"
2467  , "exchange"
2468  , "fd_double_arrow"
2469  , "fleur"
2470  , "forbidden"
2471  , "grab"
2472  , "grabbing"
2473  , "gumby"
2474  , "h_double_arrow"
2475  , "half-busy"
2476  , "hand"
2477  , "hand1"
2478  , "hand2"
2479  , "help"
2480  , "ibeam"
2481  , "left-arrow"
2482  , "left_ptr"
2483  , "left_ptr_help"
2484  , "left_ptr_watch"
2485  , "left_side"
2486  , "left_tee"
2487  , "link"
2488  , "ll_angle"
2489  , "lr_angle"
2490  , "move"
2491  , "n-resize"
2492  , "ne-resize"
2493  , "nesw-resize"
2494  , "no-drop"
2495  , "not-allowed"
2496  , "ns-resize"
2497  , "nw-resize"
2498  , "nwse-resize"
2499  , "openhand"
2500  , "pencil"
2501  , "pirate"
2502  , "plus"
2503  , "pointer"
2504  , "pointing_hand"
2505  , "progress"
2506  , "question_arrow"
2507  , "right-arrow"
2508  , "right_ptr"
2509  , "right_side"
2510  , "right_tee"
2511  , "row-resize"
2512  , "s-resize"
2513  , "sailboat"
2514  , "sb_down_arrow"
2515  , "sb_h_double_arrow"
2516  , "sb_left_arrow"
2517  , "sb_right_arrow"
2518  , "sb_up_arrow"
2519  , "sb_v_double_arrow"
2520  , "se-resize"
2521  , "shuttle"
2522  , "size-bdiag"
2523  , "size-fdiag"
2524  , "size-hor"
2525  , "size-ver"
2526  , "size_all"
2527  , "size_bdiag"
2528  , "size_fdiag"
2529  , "size_hor"
2530  , "size_ver"
2531  , "sizing"
2532  , "split_h"
2533  , "split_v"
2534  , "sw-resize"
2535  , "target"
2536  , "tcross"
2537  , "text"
2538  , "top_left_arrow"
2539  , "top_left_corner"
2540  , "top_right_corner"
2541  , "top_side"
2542  , "top_tee"
2543  , "trek"
2544  , "ul_angle"
2545  , "up-arrow"
2546  , "ur_angle"
2547  , "v_double_arrow"
2548  , "vertical-text"
2549  , "w-resize"
2550  , "wait"
2551  , "watch"
2552  , "wayland-cursor"
2553  , "whats_this"
2554  , "x-cursor"
2555  , "xterm"
2556  , "zoom-in"
2557  , "zoom-out"
2558  };
2559  */
2560  // }}}
2561 
2571  class YetaniErrorCategory_
2572  : public std::error_category
2573  {
2574  public:
2575  constexpr YetaniErrorCategory_() noexcept
2576  {
2577  }
2578 
2579  const char* name() const noexcept override
2580  {
2581  return "zakero.Yetani";
2582  }
2583 
2584  std::string message(int condition) const override
2585  {
2586  switch(condition)
2587  {
2588 #define X(name_, val_, mesg_) \
2589  case val_: return mesg_;
2590  ZAKERO_YETANI__ERROR_DATA
2591 #undef X
2592  }
2593 
2594  return "Unknown error condition";
2595  }
2596  } YetaniErrorCategory;
2597 
2598 
2603  Yetani::Lambda Lambda_DoNothing = []() noexcept {};
2604  Yetani::LambdaKey LambdaKey_DoNothing = [](const Yetani::Key&, const Yetani::KeyModifier&) noexcept {};
2605  Yetani::LambdaAxis LambdaAxis_DoNothing = [](const Yetani::PointerAxis&, const Yetani::KeyModifier&) noexcept {};
2606  Yetani::LambdaButtonMm LambdaButtonMm_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointMm&, const Yetani::KeyModifier&) noexcept {};
2607  Yetani::LambdaButtonPercent LambdaButtonPercent_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointPercent&, const Yetani::KeyModifier&) noexcept {};
2608  Yetani::LambdaButtonPixel LambdaButtonPixel_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointPixel&, const Yetani::KeyModifier&) noexcept {};
2609  Yetani::LambdaPointMm LambdaPointMm_DoNothing = [](const Yetani::PointMm&, const Yetani::KeyModifier&) noexcept {};
2610  Yetani::LambdaPointPercent LambdaPointPercent_DoNothing = [](const Yetani::PointPercent&, const Yetani::KeyModifier&) noexcept {};
2611  Yetani::LambdaPointPixel LambdaPointPixel_DoNothing = [](const Yetani::PointPixel&, const Yetani::KeyModifier&) noexcept {};
2612  Yetani::LambdaBool LambdaBool_DoNothing = [](const bool) noexcept {};
2613  Yetani::LambdaOutputId LambdaOutputId_DoNothing = [](const Yetani::OutputId) noexcept {};
2614  Yetani::LambdaWindowDecorations LambdaWindowDecorations_DoNothing = [](const Yetani::WindowDecorations) noexcept {};
2615  Yetani::LambdaWindowMode LambdaWindowMode_DoNothing = [](const Yetani::WindowMode) noexcept {};
2616  Yetani::LambdaSizeMm LambdaSizeMm_DoNothing = [](const Yetani::SizeMm&) noexcept {};
2617  Yetani::LambdaSizePercent LambdaSizePercent_DoNothing = [](const Yetani::SizePercent&) noexcept {};
2618  Yetani::LambdaSizePixel LambdaSizePixel_DoNothing = [](const Yetani::SizePixel&) noexcept {};
2635  bool equalish(const float a
2636  , const float b
2637  , const float delta
2638  ) noexcept
2639  {
2640  return (std::abs(a - b) < delta);
2641  }
2642 
2643 
2656  inline size_t sizeInBytes(const Yetani::SizePixel& size
2657  , const wl_shm_format format
2658  ) noexcept
2659  {
2660  return size.width
2661  * size.height
2663  ;
2664  };
2665 
2666 
2680  template<class Type
2681  >
2682  std::error_code validateMinMax(const Type& min
2683  , const Type& max
2684  ) noexcept
2685  {
2686  if((min.width < 0)
2687  || (min.height < 0)
2688  || (max.width < 0)
2689  || (max.height < 0)
2690  )
2691  {
2692  return ZAKERO_YETANI__ERROR(Yetani::Error_Window_Size_Too_Small);
2693  }
2694 
2695  if((min.width > 0)
2696  && (max.width > 0)
2697  && (min.width > max.width)
2698  )
2699  {
2700  return ZAKERO_YETANI__ERROR(Yetani::Error_Minimum_Size_Greater_Than_Maximum_Size);
2701  }
2702 
2703  if((min.height > 0)
2704  && (max.height > 0)
2705  && (min.height > max.height)
2706  )
2707  {
2708  return ZAKERO_YETANI__ERROR(Yetani::Error_Minimum_Size_Greater_Than_Maximum_Size);
2709  }
2710 
2711  return ZAKERO_YETANI__ERROR(Yetani::Error_None);
2712  };
2713 }
2714 
2715 // }}}
2716 // {{{ Documentation
2717 
2842 /* Disabled because Doxygen does not support "enum classes"
2843  *
2844  * \var Yetani::Released
2845  * \brief The key was released
2846  *
2847  * \var Yetani::Pressed
2848  * \brief The key was pressed
2849  *
2850  * \var Yetani::Repeat
2851  * \brief The key is being held down
2852  */
2853 
3083 // }}}
3084 // {{{ Static Member Initialization
3085 // {{{ Listener Handler : Wayland
3086 
3087 struct wl_buffer_listener Yetani::buffer_listener =
3088 { .release = &Yetani::handlerBufferRelease
3089 };
3090 
3091 struct wl_callback_listener Yetani::frame_callback_listener =
3092 { .done = &Yetani::handlerSwapBuffers
3093 };
3094 
3095 struct wl_keyboard_listener Yetani::keyboard_listener =
3096 { .keymap = &Yetani::handlerKeyboardKeymap
3097 , .enter = &Yetani::handlerKeyboardEnter
3098 , .leave = &Yetani::handlerKeyboardLeave
3099 , .key = &Yetani::handlerKeyboardKey
3100 , .modifiers = &Yetani::handlerKeyboardModifiers
3101 , .repeat_info = &Yetani::handlerKeyboardRepeatInfo
3102 };
3103 
3104 struct wl_output_listener Yetani::output_listener =
3105 { .geometry = &Yetani::handlerOutputGeometry
3106 , .mode = &Yetani::handlerOutputMode
3107 , .done = &Yetani::handlerOutputDone
3108 , .scale = &Yetani::handlerOutputScale
3109 };
3110 
3111 struct wl_pointer_listener Yetani::pointer_listener =
3112 { .enter = &Yetani::handlerPointerEnter
3113 , .leave = &Yetani::handlerPointerLeave
3114 , .motion = &Yetani::handlerPointerMotion
3115 , .button = &Yetani::handlerPointerButton
3116 , .axis = &Yetani::handlerPointerAxis
3117 , .frame = &Yetani::handlerPointerFrame
3118 , .axis_source = &Yetani::handlerPointerAxisSource
3119 , .axis_stop = &Yetani::handlerPointerAxisStop
3120 , .axis_discrete = &Yetani::handlerPointerAxisDiscrete
3121 };
3122 
3123 struct wl_registry_listener Yetani::registry_listener =
3124 { .global = &Yetani::handlerRegistryGlobal
3125 , .global_remove = &Yetani::handlerRegistryRemove
3126 };
3127 
3128 struct wl_seat_listener Yetani::seat_listener =
3129 { .capabilities = &Yetani::handlerSeatCapabilities
3130 , .name = &Yetani::handlerSeatName
3131 };
3132 
3133 struct wl_shm_listener Yetani::shm_listener =
3134 { .format = &Yetani::handlerShmFormat
3135 };
3136 
3137 struct wl_surface_listener Yetani::surface_listener =
3138 { .enter = &Yetani::handlerSurfaceEnter
3139 , .leave = &Yetani::handlerSurfaceLeave
3140 };
3141 
3142 // }}}
3143 // {{{ Listener Handler : Wayland Unstable
3144 // }}}
3145 // {{{ Listener Handler : XDG
3146 
3147 struct xdg_wm_base_listener Yetani::xdg_wm_base_listener =
3148 { .ping = &Yetani::handlerXdgWmBasePing
3149 };
3150 
3151 struct xdg_surface_listener Yetani::xdg_surface_listener =
3152 { .configure = &Yetani::handlerXdgSurfaceConfigure
3153 };
3154 
3155 struct xdg_toplevel_listener Yetani::xdg_toplevel_listener =
3156 { .configure = &Yetani::handlerXdgToplevelConfigure
3157 , .close = &Yetani::handlerXdgToplevelClose
3158 };
3159 
3160 // }}}
3161 // {{{ Listener Handler : XDG Unstable
3162 
3163 struct zxdg_toplevel_decoration_v1_listener Yetani::xdg_toplevel_decoration_listener =
3164 { .configure = &Yetani::handlerXdgToplevelDecorationConfigure
3165 };
3166 
3167 // }}}
3168 // }}}
3169 // {{{ Constructor / Destructor
3170 
3176 Yetani::Yetani() noexcept
3177  : cursor_map()
3178  , cursor_surface_map()
3179  , cursor_memory_pool(
3180  std::string("Zakero.Yetani.")
3181  + std::to_string(ZAKERO_STEADY_TIME_NOW(nanoseconds))
3182  )
3183  , cursor_mutex()
3184  , cursor_shm_pool(nullptr)
3185  , cursor_pointer(nullptr)
3186  , event_loop()
3187  , event_loop_is_running(false)
3188  , compositor(nullptr)
3189  , display(nullptr)
3190  , registry(nullptr)
3191  , shm(nullptr)
3192  , shm_format_vector()
3193  , seat_map()
3194  , id_to_seat()
3195  , seat(nullptr)
3196  , keyboard()
3197  , pointer()
3198  , output_data()
3199  , on_output_add(LambdaOutputId_DoNothing)
3200  , on_output_change(LambdaOutputId_DoNothing)
3201  , on_output_remove(LambdaOutputId_DoNothing)
3202  , output_changes_map()
3203  , output_state_map()
3204  , output_notify_surface_vector()
3205  , buffer()
3206  , surface_event_map()
3207  , surface_extent_map()
3208  , surface_extent_mutex()
3209  , surface_frame_map()
3210  , surface_size_map()
3211  , surface_resize_mutex_map()
3212  , window_vector()
3213  , window_vector_mutex()
3214  , xdg_state_change_map()
3215  , xdg_state_change_mutex()
3216  , xdg_wm_base(nullptr)
3217  , xdg_surface_map()
3218  , xdg_toplevel_map()
3219  , xdg_decoration_map()
3220  , decoration_manager(nullptr)
3221 {
3222 }
3223 
3224 
3235 {
3236  if(event_loop_is_running || event_loop.joinable())
3237  {
3238  event_loop.request_stop();
3239  event_loop.join();
3240  }
3241 
3242  disconnect();
3243 }
3244 
3245 // }}}
3246 // {{{ Connection
3247 
3271 {
3272  std::error_code error;
3273 
3274  return Yetani::connect("", error);
3275 }
3276 
3277 
3302 Yetani* Yetani::connect(const std::string& display
3303  ) noexcept
3304 {
3305  std::error_code error;
3306 
3307  return Yetani::connect(display, error);
3308 }
3309 
3310 
3338 Yetani* Yetani::connect(std::error_code& error
3339  ) noexcept
3340 {
3341  return Yetani::connect("", error);
3342 }
3343 
3373 Yetani* Yetani::connect(const std::string& display
3374  , std::error_code& error
3375  ) noexcept
3376 {
3377  Yetani* yetani = new Yetani();
3378 
3379  const char* display_name = nullptr;
3380 
3381  if(display.empty() == false)
3382  {
3383  display_name = display.c_str();
3384  }
3385 
3386  // --- Get the Display --- //
3387  yetani->display = wl_display_connect(display_name);
3388  if(yetani->display == nullptr)
3389  {
3390  delete yetani;
3391 
3392  const char* session = getenv("XDG_SESSION_TYPE");
3393 
3394  if(session != nullptr
3395  && strcasecmp(session, "wayland") != 0
3396  )
3397  {
3398  error = ZAKERO_YETANI__ERROR(Error_Wayland_Not_Available);
3399  }
3400  else if(display.empty())
3401  {
3402  error = ZAKERO_YETANI__ERROR(Error_Connection_Failed);
3403  }
3404  else
3405  {
3406  error = ZAKERO_YETANI__ERROR(Error_Invalid_Display_Name);
3407  }
3408 
3409  return nullptr;
3410  }
3411 
3412  // --- Get the Registry --- //
3413  yetani->registry = wl_display_get_registry(yetani->display);
3414  if(yetani->registry == nullptr)
3415  {
3416  delete yetani;
3417 
3418  error = ZAKERO_YETANI__ERROR(Error_Registry_Not_Available);
3419 
3420  return nullptr;
3421  }
3422 
3423  wl_registry_add_listener(yetani->registry, &registry_listener, yetani);
3424 
3425  // --- Wait for all Global Objects to be registered --- //
3426  wl_display_dispatch(yetani->display);
3427  wl_display_roundtrip(yetani->display);
3428 
3429  // --- Validate required Global Objects --- //
3430  if(yetani->compositor == nullptr)
3431  {
3432  delete yetani;
3433 
3434  error = ZAKERO_YETANI__ERROR(Error_Compositor_Was_Not_Found);
3435 
3436  return nullptr;
3437  }
3438 
3439  if(yetani->shm == nullptr)
3440  {
3441  delete yetani;
3442 
3443  error = ZAKERO_YETANI__ERROR(Error_Shm_Was_Not_Found);
3444 
3445  return nullptr;
3446  }
3447 
3448  if(yetani->xdg_wm_base == nullptr)
3449  {
3450  delete yetani;
3451 
3452  error = ZAKERO_YETANI__ERROR(Error_Xdg_WM_Base_Was_Not_Found);
3453 
3454  return nullptr;
3455  }
3456 
3457  yetani->cursorSetup();
3458 
3459  yetani->eventLoopStart();
3460 
3461  error = ZAKERO_YETANI__ERROR(Error_None);
3462 
3463  return yetani;
3464 }
3465 
3466 
3476 void Yetani::disconnect() noexcept
3477 {
3478  cursorTeardown();
3479 
3480  if(decoration_manager != nullptr)
3481  {
3482  zxdg_decoration_manager_v1_destroy(decoration_manager);
3483  decoration_manager = nullptr;
3484  }
3485 
3486  if(xdg_wm_base != nullptr)
3487  {
3488  xdg_wm_base_destroy(xdg_wm_base);
3489  xdg_wm_base = nullptr;
3490  }
3491 
3492  if(shm != nullptr)
3493  {
3494  wl_shm_destroy(shm);
3495  shm = nullptr;
3496  }
3497 
3498  // Seat
3499  id_to_seat.clear();
3500 
3501  while(seat_map.empty() == false)
3502  {
3503  auto iter = std::begin(seat_map);
3504 
3505  struct wl_seat* wl_seat = iter->first;
3506 
3507  seatDestroy(wl_seat);
3508  }
3509 
3510  // Wayland Output Devices
3511  {
3512  std::lock_guard<std::mutex> lock(output_data.mutex);
3513 
3514  for(auto& iter : output_data.output_map)
3515  {
3516  struct wl_output* wayland_output = iter.first;
3517 
3518  wl_output_destroy(wayland_output);
3519  }
3520 
3521  output_changes_map.clear();
3522  output_state_map.clear();
3523  output_data.output_map.clear();
3524  output_data.wloutput_to_outputid.clear();
3525  output_data.outputid_to_wloutput.clear();
3526  }
3527 
3528  if(registry != nullptr)
3529  {
3530  wl_registry_destroy(registry);
3531  registry = nullptr;
3532  }
3533 
3534  if(compositor != nullptr)
3535  {
3536  wl_compositor_destroy(compositor);
3537  compositor = nullptr;
3538  }
3539 
3540  if(display != nullptr)
3541  {
3542  wl_display_disconnect(display);
3543  display = nullptr;
3544  }
3545 
3546  return;
3547 }
3548 
3549 // }}}
3550 // {{{ Cursor
3551 
3684 void Yetani::cursorAnimate() noexcept
3685 {
3686  int64_t time_now = ZAKERO_STEADY_TIME_NOW(milliseconds);
3687 
3688  std::lock_guard<std::mutex> lock(cursor_mutex);
3689 
3690  for(auto& iter : cursor_map)
3691  {
3692  Yetani::Cursor& cursor = iter.second;
3693 
3694  if(cursor.next_frame_time <= time_now)
3695  {
3696  const int64_t time_over = time_now - cursor.next_frame_time;
3697  cursor.next_frame_time = time_now + cursor.time_per_frame - time_over;
3698 
3699  cursor.buffer_index = (cursor.buffer_index + 1) % cursor.buffer_vector.size();
3700 
3701  wl_surface_attach(cursor.wl_surface, cursor.buffer_vector[cursor.buffer_index], 0, 0);
3702  wl_surface_damage(cursor.wl_surface
3703  , 0, 0
3704  , cursor.width, cursor.height
3705  );
3706 
3707  wl_surface_commit(cursor.wl_surface);
3708  }
3709  }
3710 }
3711 
3712 
3753 std::error_code Yetani::cursorCreate(const std::string& name
3754  , const Yetani::CursorConfig& config
3755  ) noexcept
3756 {
3757  if(name.empty())
3758  {
3759  return ZAKERO_YETANI__ERROR(Error_Cursor_Name_Is_Invalid);
3760  }
3761 
3762  if(cursor_map.contains(name) == true)
3763  {
3764  return ZAKERO_YETANI__ERROR(Error_Cursor_Already_Exists);
3765  }
3766 
3767  if(config.size.width <= 0 || config.size.height <= 0)
3768  {
3769  return ZAKERO_YETANI__ERROR(Error_Cursor_Size_Too_Small);
3770  }
3771 
3772  if(config.image_data.empty())
3773  {
3774  return ZAKERO_YETANI__ERROR(Error_Cursor_Image_Data_Is_Empty);
3775  }
3776  else if(config.image_data.size() > 1)
3777  {
3778  if(config.time_per_frame.count() <= 0)
3779  {
3780  return ZAKERO_YETANI__ERROR(Error_Cursor_Frame_Time_Too_Small);
3781  }
3782 
3783  if(config.time_per_frame.count() > Size_Max)
3784  {
3785  return ZAKERO_YETANI__ERROR(Error_Cursor_Frame_Time_Too_Large);
3786  }
3787  }
3788 
3789  std::error_code error = cursorCreateCursor(name, config);
3790 
3791  return error;
3792 }
3793 
3794 
3805 std::error_code Yetani::cursorCreateCursor(const std::string& cursor_name
3806  , const Yetani::CursorConfig& cursor_config
3807  ) noexcept
3808 {
3809  const uint8_t bytes_per_pixel = shmFormatBytesPerPixel(cursor_config.format);
3810  const size_t frame_count = cursor_config.image_data.size();
3811 
3812  Yetani::Cursor cursor =
3813  { .wl_surface = wl_compositor_create_surface(compositor)
3814  , .buffer_vector = { frame_count, nullptr }
3815  , .format = cursor_config.format
3816  , .next_frame_time = ZAKERO_STEADY_TIME_NOW(milliseconds)
3817  , .buffer_index = 0
3818  , .time_per_frame = uint32_t(cursor_config.time_per_frame.count())
3819  , .width = cursor_config.size.width
3820  , .height = cursor_config.size.height
3821  , .hotspot_x = cursor_config.hotspot_x
3822  , .hotspot_y = cursor_config.hotspot_y
3823  };
3824 
3825  if(cursor.time_per_frame == 0)
3826  {
3827  cursor.time_per_frame = Size_Max;
3828  }
3829 
3830  const int stride = cursor.width * bytes_per_pixel;
3831  const size_t image_size = stride * cursor.height;
3832 
3833  for(size_t i = 0; i < frame_count; i++)
3834  {
3835  std::error_code error;
3836 
3837  off_t offset = cursor_memory_pool.alloc(image_size, error);
3838  if(error)
3839  {
3840  while(i > 0)
3841  {
3842  i--;
3843 
3844  struct wl_buffer* buffer = cursor.buffer_vector[i];
3845  cursor.buffer_vector[i] = nullptr;
3846 
3847  off_t offset = (off_t)wl_buffer_get_user_data(buffer);
3848  wl_buffer_destroy(buffer);
3849 
3850  cursor_memory_pool.free(offset);
3851  }
3852 
3853  return error;
3854  }
3855 
3856  uint32_t* p = (uint32_t*)cursor_memory_pool.addressOf(offset);
3857  memcpy(p, (uint8_t*)cursor_config.image_data[i], image_size);
3858 
3859  cursor.buffer_vector[i] = wl_shm_pool_create_buffer(cursor_shm_pool
3860  , offset
3861  , cursor.width
3862  , cursor.height
3863  , stride
3864  , cursor.format
3865  );
3866 
3867  wl_buffer_set_user_data(cursor.buffer_vector[i], (void*)offset);
3868  }
3869 
3870  wl_surface_attach(cursor.wl_surface, cursor.buffer_vector[0], 0, 0);
3871  wl_surface_commit(cursor.wl_surface);
3872 
3873  std::lock_guard<std::mutex> lock(cursor_mutex);
3874 
3875  cursor_map[cursor_name] = cursor;
3876 
3877  return ZAKERO_YETANI__ERROR(Error_None);
3878 }
3879 
3880 
3891 std::error_code Yetani::cursorDestroy(const std::string& name
3892  ) noexcept
3893 {
3894  Yetani::Cursor cursor;
3895 
3896  {
3897  std::lock_guard<std::mutex> lock(cursor_mutex);
3898 
3899  if(cursor_map.contains(name) == false)
3900  {
3901  return ZAKERO_YETANI__ERROR(Error_Cursor_Does_Not_Exist);
3902  }
3903 
3904  cursor = cursor_map[name];
3905 
3906  cursor_map.erase(name);
3907  }
3908 
3909  auto iter = std::begin(cursor_surface_map);
3910  auto iter_end = std::end(cursor_surface_map);
3911  while(iter != iter_end)
3912  {
3913  if(cursor.wl_surface == iter->second.wl_surface)
3914  {
3915  iter = cursor_surface_map.erase(iter);
3916  }
3917  else
3918  {
3919  iter++;
3920  }
3921  }
3922 
3923  if(cursor.wl_surface)
3924  {
3925  wl_surface_destroy(cursor.wl_surface);
3926  cursor.wl_surface = nullptr;
3927  }
3928 
3929  for(wl_buffer* buffer : cursor.buffer_vector)
3930  {
3931  off_t offset = (off_t)wl_buffer_get_user_data(buffer);
3932  wl_buffer_destroy(buffer);
3933 
3934  cursor_memory_pool.free(offset);
3935  }
3936 
3937  return ZAKERO_YETANI__ERROR(Error_None);
3938 }
3939 
3940 
3949 void Yetani::cursorEnter(wl_pointer* wl_pointer
3950  , uint32_t serial
3951  , struct wl_surface* wl_surface
3952  ) noexcept
3953 {
3954  std::lock_guard<std::mutex> lock(cursor_mutex);
3955 
3956  cursor_pointer = wl_pointer;
3957 
3958  if(cursor_surface_map.contains(wl_surface) == false)
3959  {
3960  return;
3961  }
3962 
3963  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
3964 
3965  cursor_surface.wl_pointer = wl_pointer;
3966  cursor_surface.serial = serial;
3967 
3968  if(cursor_surface.is_visible)
3969  {
3970  wl_pointer_set_cursor(cursor_surface.wl_pointer
3971  , cursor_surface.serial
3972  , cursor_surface.wl_surface
3973  , cursor_surface.hotspot_x
3974  , cursor_surface.hotspot_y
3975  );
3976  }
3977  else
3978  {
3979  wl_pointer_set_cursor(cursor_surface.wl_pointer
3980  , cursor_surface.serial
3981  , nullptr
3982  , 0
3983  , 0
3984  );
3985  }
3986 }
3987 
3988 
3998 void Yetani::cursorLeave(struct wl_surface* wl_surface
3999  ) noexcept
4000 {
4001  std::lock_guard<std::mutex> lock(cursor_mutex);
4002 
4003  cursor_pointer = nullptr;
4004 
4005  if(cursor_surface_map.contains(wl_surface) == false)
4006  {
4007  return;
4008  }
4009 
4010  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4011 
4012  cursor_surface.wl_pointer = nullptr;
4013  cursor_surface.serial = 0;
4014 }
4015 
4016 
4024 void Yetani::cursorHide(struct wl_surface* wl_surface
4025  ) noexcept
4026 {
4027  std::lock_guard<std::mutex> lock(cursor_mutex);
4028 
4029  if(cursor_surface_map.contains(wl_surface) == false)
4030  {
4031  return;
4032  }
4033 
4034  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4035 
4036  cursor_surface.is_visible = false;
4037 
4038  if(cursor_surface.wl_pointer != nullptr)
4039  {
4040  wl_pointer_set_cursor(cursor_surface.wl_pointer
4041  , cursor_surface.serial
4042  , nullptr
4043  , 0
4044  , 0
4045  );
4046  }
4047 }
4048 
4049 
4057 void Yetani::cursorShow(struct wl_surface* wl_surface
4058  ) noexcept
4059 {
4060  std::lock_guard<std::mutex> lock(cursor_mutex);
4061 
4062  if(cursor_surface_map.contains(wl_surface) == false)
4063  {
4064  return;
4065  }
4066 
4067  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4068 
4069  cursor_surface.is_visible = true;
4070 
4071  if(cursor_surface.wl_pointer != nullptr)
4072  {
4073  wl_pointer_set_cursor(cursor_surface.wl_pointer
4074  , cursor_surface.serial
4075  , cursor_surface.wl_surface
4076  , cursor_surface.hotspot_x
4077  , cursor_surface.hotspot_y
4078  );
4079  }
4080 }
4081 
4082 
4093 bool Yetani::cursorIsHidden(struct wl_surface* wl_surface
4094  ) const noexcept
4095 {
4096  std::lock_guard<std::mutex> lock(cursor_mutex);
4097 
4098  if(cursor_surface_map.contains(wl_surface) == false)
4099  {
4100  return true;
4101  }
4102 
4103  const Yetani::CursorSurface& cursor_surface = cursor_surface_map.at(wl_surface);
4104 
4105  return !(cursor_surface.is_visible);
4106 }
4107 
4108 
4116 void Yetani::cursorSetup() noexcept
4117 {
4118  cursor_map.clear();
4119 
4120  uint64_t bytes = zakero::convert((uint64_t)4, zakero::Storage::Kilobyte, zakero::Storage::Byte);
4121  cursor_memory_pool.init(bytes, true, zakero::MemoryPool::Alignment::Bits_32);
4122 
4123  cursor_memory_pool.sizeOnChange([&](size_t new_size)
4124  {
4125  wl_shm_pool_resize(cursor_shm_pool, new_size);
4126  });
4127 
4128  cursor_shm_pool = wl_shm_create_pool(shm, cursor_memory_pool.fd(), cursor_memory_pool.size());
4129 }
4130 
4131 
4139 void Yetani::cursorTeardown() noexcept
4140 {
4141  while(cursor_map.empty() == false)
4142  {
4143  const auto& iter = cursor_map.begin();
4144 
4145  const std::string& name = iter->first;
4146 
4147  cursorDestroy(name);
4148  }
4149 
4150  if(cursor_shm_pool != nullptr)
4151  {
4152  wl_shm_pool_destroy(cursor_shm_pool);
4153  }
4154 }
4155 
4156 
4168 std::error_code Yetani::cursorAttach(const std::string& cursor_name
4169  , struct wl_surface* wl_surface
4170  ) noexcept
4171 {
4172  std::lock_guard<std::mutex> lock(cursor_mutex);
4173 
4174  if(cursor_map.contains(cursor_name) == false)
4175  {
4176  return ZAKERO_YETANI__ERROR(Error_Cursor_Does_Not_Exist);
4177  }
4178 
4179  if(cursor_surface_map.contains(wl_surface) == false)
4180  {
4181  cursor_surface_map[wl_surface] =
4182  { .wl_pointer = cursor_pointer
4183  , .wl_surface = nullptr
4184  , .serial = 0
4185  , .hotspot_x = 0
4186  , .hotspot_y = 0
4187  , .is_visible = true
4188  };
4189  }
4190 
4191  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4192  Yetani::Cursor& cursor = cursor_map[cursor_name];
4193 
4194  cursor_surface.wl_surface = cursor.wl_surface;
4195  cursor_surface.hotspot_x = cursor.hotspot_x;
4196  cursor_surface.hotspot_y = cursor.hotspot_y;
4197 
4198  if(cursor_surface.wl_pointer != nullptr)
4199  {
4200  if(cursor_surface.is_visible)
4201  {
4202  wl_pointer_set_cursor(cursor_surface.wl_pointer
4203  , cursor_surface.serial
4204  , cursor_surface.wl_surface
4205  , cursor_surface.hotspot_x
4206  , cursor_surface.hotspot_y
4207  );
4208  }
4209  else
4210  {
4211  wl_pointer_set_cursor(cursor_surface.wl_pointer
4212  , cursor_surface.serial
4213  , nullptr
4214  , 0
4215  , 0
4216  );
4217  }
4218  }
4219 
4220  return ZAKERO_YETANI__ERROR(Error_None);
4221 }
4222 
4223 
4235 std::error_code Yetani::cursorDetach(struct wl_surface* wl_surface
4236  ) noexcept
4237 {
4238  std::lock_guard<std::mutex> lock(cursor_mutex);
4239 
4240  if(cursor_surface_map.contains(wl_surface) == false)
4241  {
4242  return ZAKERO_YETANI__ERROR(Error_Cursor_Not_Attached);
4243  }
4244 
4245  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4246 
4247  if(cursor_surface.wl_pointer != nullptr)
4248  {
4249  wl_pointer_set_cursor(cursor_surface.wl_pointer
4250  , cursor_surface.serial
4251  , nullptr
4252  , 0
4253  , 0
4254  );
4255  }
4256 
4257  cursor_surface_map.erase(wl_surface);
4258 
4259  return ZAKERO_YETANI__ERROR(Error_None);
4260 }
4261 
4262 // }}}
4263 // {{{ Event Loop
4264 
4265 //#define ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4266 
4275 void Yetani::eventLoopStart() noexcept
4276 {
4277  event_loop = std::jthread(&Yetani::eventLoop, this);
4278 
4279  while(event_loop_is_running.load() == false)
4280  {
4281  // Wait for the thread to start
4282  std::this_thread::sleep_for(std::chrono::nanoseconds(42));
4283  }
4284 
4285  #ifdef ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4286  int policy = SCHED_FIFO;
4287  int priority_min = sched_get_priority_min(policy);
4288  int priority_max = sched_get_priority_max(policy);
4289 
4290  sched_param sched =
4291  { .sched_priority = (priority_min + priority_max) / 2
4292  };
4293 
4294  pthread_setschedparam(event_loop.native_handle(), policy, &sched);
4295  #endif
4296 }
4297 
4298 
4326 void Yetani::eventLoop(std::stop_token thread_token
4327  , Yetani* yetani
4328  ) noexcept
4329 {
4330  struct pollfd fd_status =
4331  { .fd = wl_display_get_fd(yetani->display)
4332  , .events = POLLIN | POLLOUT
4333  , .revents = 0
4334  };
4335 
4336  yetani->event_loop_is_running.store(true);
4337 
4338  // Handle events and render window contents
4339  while(thread_token.stop_requested() == false)
4340  {
4341  poll(&fd_status, 1, 1);
4342 
4343  if(fd_status.revents & POLLIN)
4344  {
4345  wl_display_dispatch(yetani->display);
4346  }
4347 
4348  yetani->cursorAnimate();
4349 
4350  keyboardRepeat(yetani->keyboard);
4351 
4352  if(fd_status.revents & POLLOUT)
4353  {
4354  wl_display_flush(yetani->display);
4355  }
4356 
4357  #ifdef ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4358  std::this_thread::yield();
4359  #endif
4360  }
4361 
4362  yetani->event_loop_is_running.store(false);
4363 }
4364 
4365 // }}}
4366 // {{{ Shared Memory
4367 
4378 const Yetani::VectorShmFormat& Yetani::shmFormatAvailable() const noexcept
4379 {
4380  return shm_format_vector;
4381 }
4382 
4383 
4395 uint8_t Yetani::shmFormatBytesPerPixel(const wl_shm_format shm_format
4396  ) noexcept
4397 {
4398  switch(shm_format)
4399  {
4400 #define X(value_, bytes_, desc_) \
4401  case value_: return bytes_;
4402  ZAKERO_YETANI__SHM_FORMAT
4403 #undef X
4404  default: return 0;
4405  }
4406 }
4407 
4408 
4420 std::string Yetani::shmFormatDescription(const wl_shm_format shm_format
4421  ) noexcept
4422 {
4423  switch(shm_format)
4424  {
4425 #define X(value_, bytes_, desc_) \
4426  case value_: return desc_;
4427  ZAKERO_YETANI__SHM_FORMAT
4428 #undef X
4429  default: return "";
4430  }
4431 }
4432 
4433 
4443 std::string Yetani::shmFormatName(const wl_shm_format shm_format
4444  ) noexcept
4445 {
4446  switch(shm_format)
4447  {
4448 #define X(value_, bytes_, desc_) \
4449  case value_: return #value_;
4450  ZAKERO_YETANI__SHM_FORMAT
4451 #undef X
4452  default: return "";
4453  }
4454 }
4455 
4456 // }}}
4457 // {{{ Utility
4458 
4459 
4460 // }}}
4461 // {{{ Wayland : Buffer
4462 
4503 struct wl_buffer* Yetani::bufferCreate(Yetani::SurfaceSize& surface_size
4504  , Yetani::Window::Memory* window_memory
4505  , Yetani::Buffer* buffer
4506  ) noexcept
4507 {
4508  off_t offset = window_memory->memory_pool.alloc(surface_size.in_bytes);
4509 
4510  struct wl_buffer* wl_buffer = wl_shm_pool_create_buffer(window_memory->wl_shm_pool
4511  , offset
4512  , surface_size.width
4513  , surface_size.height
4514  , surface_size.stride
4515  , surface_size.pixel_format
4516  );
4517 
4518  wl_buffer_set_user_data(wl_buffer, buffer);
4519 
4520  buffer->mutex.lock();
4521  {
4522  buffer->map[wl_buffer] =
4523  { .memory_pool = &window_memory->memory_pool
4524  , .offset = offset
4525  };
4526  }
4527  buffer->mutex.unlock();
4528 
4529  return wl_buffer;
4530 }
4531 
4532 
4544 struct wl_buffer* Yetani::bufferCreateAndRelease(Yetani* yetani
4545  , Yetani::SurfaceSize& surface_size
4546  , Yetani::Window::Memory* window_memory
4547  ) noexcept
4548 {
4549  struct wl_buffer* wl_buffer = bufferCreate(surface_size, window_memory, &yetani->buffer);
4550 
4551  wl_buffer_add_listener(wl_buffer
4552  , &Yetani::buffer_listener
4553  , &yetani->buffer
4554  );
4555 
4556  return wl_buffer;
4557 }
4558 
4559 
4569 void Yetani::bufferDestroy(struct wl_buffer*& wl_buffer
4570  ) noexcept
4571 {
4572  Yetani::Buffer* buffer = (Yetani::Buffer*)wl_buffer_get_user_data(wl_buffer);
4573 
4574  wl_buffer_destroy(wl_buffer);
4575 
4576  buffer->mutex.lock();
4577  {
4578  BufferData& buffer_data = buffer->map[wl_buffer];
4579 
4580  buffer_data.memory_pool->free(buffer_data.offset);
4581 
4582  buffer->map.erase(wl_buffer);
4583  }
4584  buffer->mutex.unlock();
4585 
4586  wl_buffer = nullptr;
4587 }
4588 
4589 // }}}
4590 // {{{ Wayland : Output
4591 
4687 Yetani::Output Yetani::output(Yetani::OutputId output_id
4688  ) const noexcept
4689 {
4690  std::lock_guard<std::mutex> lock(output_data.mutex);
4691 
4692  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4693  {
4694  ZAKERO_YETANI__DEBUG
4695  << "Invalid output_id: "
4696  << std::to_string(output_id)
4697  ;
4698 
4699  return {};
4700  }
4701 
4702  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4703 
4704  return output_data.output_map.at(wl_output);
4705 }
4706 
4707 
4719 Yetani::VectorOutputId Yetani::outputVector() const noexcept
4720 {
4721  Yetani::VectorOutputId vector;
4722 
4723  std::lock_guard<std::mutex> lock(output_data.mutex);
4724 
4725  for(const auto& iter : output_data.outputid_to_wloutput)
4726  {
4727  vector.push_back(iter.first);
4728  }
4729 
4730  return vector;
4731 }
4732 
4733 
4745 std::string Yetani::outputSubpixelName(int32_t subpixel_format
4746  ) noexcept
4747 {
4748  switch(subpixel_format)
4749  {
4750 #define X(value_, name_) \
4751  case value_: return name_;
4752  ZAKERO_YETANI__OUTPUT_SUBPIXEL
4753 #undef X
4754  default: return "";
4755  }
4756 }
4757 
4758 
4770 std::string Yetani::outputTransformName(int32_t transform
4771  ) noexcept
4772 {
4773  switch(transform)
4774  {
4775 #define X(value_, name_) \
4776  case value_: return name_;
4777  ZAKERO_YETANI__OUTPUT_TRANSFORM
4778 #undef X
4779  default: return "";
4780  }
4781 }
4782 
4783 
4794 Yetani::PointMm Yetani::outputConvertToMm(const Yetani::OutputId output_id
4795  , const Yetani::PointPixel& point
4796  ) const noexcept
4797 {
4798  std::lock_guard<std::mutex> lock(output_data.mutex);
4799 
4800  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4801  {
4802  return { point.time, 0, 0 };
4803  }
4804 
4805  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4806  const Yetani::Output& output = output_data.output_map.at(wl_output);
4807 
4808  auto p = convertPixelToMm(output, point.x, point.y);
4809 
4810  return { point.time, p.first, p.second };
4811 }
4812 
4813 
4824 Yetani::PointPercent Yetani::outputConvertToPercent(const Yetani::OutputId output_id
4825  , const Yetani::PointPixel& point
4826  ) const noexcept
4827 {
4828  std::lock_guard<std::mutex> lock(output_data.mutex);
4829 
4830  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4831  {
4832  return { point.time, 0, 0 };
4833  }
4834 
4835  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4836  const Yetani::Output& output = output_data.output_map.at(wl_output);
4837 
4838  auto p = convertPixelToPercent(output, point.x, point.y);
4839 
4840  return { point.time, p.first, p.second };
4841 }
4842 
4843 
4854 Yetani::PointPixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4855  , const Yetani::PointMm& point
4856  ) const noexcept
4857 {
4858  std::lock_guard<std::mutex> lock(output_data.mutex);
4859 
4860  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4861  {
4862  return { point.time, 0, 0 };
4863  }
4864 
4865  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4866  const Yetani::Output& output = output_data.output_map.at(wl_output);
4867 
4868  auto p = convertMmToPixel(output, point.x, point.y);
4869 
4870  return { point.time, p.first, p.second };
4871 }
4872 
4873 
4884 Yetani::PointPixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4885  , const Yetani::PointPercent& point
4886  ) const noexcept
4887 {
4888  std::lock_guard<std::mutex> lock(output_data.mutex);
4889 
4890  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4891  {
4892  return { point.time, 0, 0 };
4893  }
4894 
4895  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4896  const Yetani::Output& output = output_data.output_map.at(wl_output);
4897 
4898  auto p = convertPercentToPixel(output, point.x, point.y);
4899 
4900  return { point.time, p.first, p.second };
4901 }
4902 
4903 
4914 Yetani::SizeMm Yetani::outputConvertToMm(const Yetani::OutputId output_id
4915  , const Yetani::SizePixel& size
4916  ) const noexcept
4917 {
4918  std::lock_guard<std::mutex> lock(output_data.mutex);
4919 
4920  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4921  {
4922  return { 0, 0 };
4923  }
4924 
4925  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4926  const Yetani::Output& output = output_data.output_map.at(wl_output);
4927 
4928  auto p = convertPixelToMm(output, size.width, size.height);
4929 
4930  return { p.first, p.second };
4931 }
4932 
4933 
4944 Yetani::SizePercent Yetani::outputConvertToPercent(const Yetani::OutputId output_id
4945  , const Yetani::SizePixel& size
4946  ) const noexcept
4947 {
4948  std::lock_guard<std::mutex> lock(output_data.mutex);
4949 
4950  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4951  {
4952  return { 0, 0 };
4953  }
4954 
4955  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4956  const Yetani::Output& output = output_data.output_map.at(wl_output);
4957 
4958  auto p = convertPixelToPercent(output, size.width, size.height);
4959 
4960  return { p.first, p.second };
4961 }
4962 
4963 
4973 Yetani::SizePixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4974  , const Yetani::SizeMm& size
4975  ) const noexcept
4976 {
4977  std::lock_guard<std::mutex> lock(output_data.mutex);
4978 
4979  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4980  {
4981  return { 0, 0 };
4982  }
4983 
4984  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4985  const Yetani::Output& output = output_data.output_map.at(wl_output);
4986 
4987  auto p = convertMmToPixel(output, size.width, size.height);
4988 
4989  return { p.first, p.second };
4990 }
4991 
4992 
5002 Yetani::SizePixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
5003  , const Yetani::SizePercent& size
5004  ) const noexcept
5005 {
5006  std::lock_guard<std::mutex> lock(output_data.mutex);
5007 
5008  if(output_data.outputid_to_wloutput.contains(output_id) == false)
5009  {
5010  return { 0, 0 };
5011  }
5012 
5013  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
5014  const Yetani::Output& output = output_data.output_map.at(wl_output);
5015 
5016  auto p = convertPercentToPixel(output, size.width, size.height);
5017 
5018  return { p.first, p.second };
5019 }
5020 
5021 
5031 void Yetani::outputOnAdd(LambdaOutputId lambda
5032  ) noexcept
5033 {
5034  if(lambda == nullptr)
5035  {
5036  on_output_add = LambdaOutputId_DoNothing;
5037  }
5038  else
5039  {
5040  on_output_add = lambda;
5041  }
5042 }
5043 
5044 
5054 void Yetani::outputOnChange(LambdaOutputId lambda
5055  ) noexcept
5056 {
5057  if(lambda == nullptr)
5058  {
5059  on_output_change = LambdaOutputId_DoNothing;
5060  }
5061  else
5062  {
5063  on_output_change = lambda;
5064  }
5065 }
5066 
5067 
5077 void Yetani::outputOnRemove(LambdaOutputId lambda
5078  ) noexcept
5079 {
5080  if(lambda == nullptr)
5081  {
5082  on_output_remove = LambdaOutputId_DoNothing;
5083  }
5084  else
5085  {
5086  on_output_remove = lambda;
5087  }
5088 }
5089 
5090 
5099 void Yetani::convertPixel(struct wl_surface* wl_surface
5100  , const int32_t pixel_xw
5101  , const int32_t pixel_yh
5102  , float& mm_xw
5103  , float& mm_yh
5104  , float& pc_xw
5105  , float& pc_yh
5106  ) const noexcept
5107 {
5108  std::lock_guard<std::mutex> lock(output_data.mutex);
5109 
5110  const Yetani::VectorWlOutput& vector = output_data.surface_output_map.at(wl_surface);
5111  struct wl_output* wl_output = vector.front();
5112  const Yetani::Output& output = output_data.output_map.at(wl_output);
5113 
5114  auto mm = convertPixelToMm(output, pixel_xw, pixel_yh);
5115  mm_xw = mm.first;
5116  mm_yh = mm.second;
5117 
5118  auto pc = convertPixelToPercent(output, pixel_xw, pixel_yh);
5119  pc_xw = pc.first;
5120  pc_yh = pc.second;
5121 }
5122 
5123 
5135 std::pair<float, float> Yetani::convertPixelToMm(const Yetani::Output& output
5136  , int32_t xw
5137  , int32_t yh
5138  ) const noexcept
5139 {
5140  const float ratio_h = output.pixels_per_mm_horizontal;
5141  const float ratio_v = output.pixels_per_mm_vertical;
5142 
5143  return
5144  { xw / ratio_h
5145  , yh / ratio_v
5146  };
5147 }
5148 
5149 
5161 std::pair<float, float> Yetani::convertPixelToPercent(const Yetani::Output& output
5162  , int32_t xw
5163  , int32_t yh
5164  ) const noexcept
5165 {
5166  return
5167  { float(xw) / output.width
5168  , float(yh) / output.height
5169  };
5170 }
5171 
5172 
5184 std::pair<int32_t, int32_t> Yetani::convertMmToPixel(const Yetani::Output& output
5185  , float xw
5186  , float yh
5187  ) const noexcept
5188 {
5189  const float ratio_h = output.pixels_per_mm_horizontal;
5190  const float ratio_v = output.pixels_per_mm_vertical;
5191 
5192  return
5193  { int32_t(xw * ratio_h)
5194  , int32_t(yh * ratio_v)
5195  };
5196 }
5197 
5198 
5210 std::pair<int32_t, int32_t> Yetani::convertPercentToPixel(const Yetani::Output& output
5211  , float xw
5212  , float yh
5213  ) const noexcept
5214 {
5215  return
5216  { int32_t(xw * output.width)
5217  , int32_t(yh * output.height)
5218  };
5219 }
5220 
5221 
5233 void Yetani::outputNotifySurface(Yetani* yetani
5234  , struct wl_output* wl_output
5235  , struct wl_surface* wl_surface
5236  ) noexcept
5237 {
5238  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
5239  if(surface_extent.preferred_unit == Yetani::SizeUnit::Pixel)
5240  {
5241  return;
5242  }
5243 
5244  Yetani::OutputData& output_data = yetani->output_data;
5245 
5246  std::lock_guard<std::mutex> lock(output_data.mutex);
5247 
5248  Yetani::VectorWlOutput& output_vector = output_data.surface_output_map[wl_surface];
5249 
5250  struct wl_output* output_current = output_vector.front();
5251 
5252  if(output_current != wl_output)
5253  {
5254  return;
5255  }
5256 
5257  Yetani::Output& output = output_data.output_map.at(wl_output);
5258  Yetani::SizePixel new_size = surface_extent.size_pixel;
5259 
5260  if(surface_extent.preferred_unit == Yetani::SizeUnit::Millimeter)
5261  {
5262  auto p = yetani->convertMmToPixel(output, surface_extent.size_mm.width, surface_extent.size_mm.height);
5263  new_size = { p.first, p.second };
5264  }
5265  else if(surface_extent.preferred_unit == Yetani::SizeUnit::Percent)
5266  {
5267  auto p = yetani->convertPercentToPixel(output, surface_extent.size_percent.width, surface_extent.size_percent.height);
5268  new_size = { p.first, p.second };
5269  }
5270 
5271  if(new_size.width <= 0)
5272  {
5273  new_size.width = 1;
5274  }
5275 
5276  if(new_size.height <= 0)
5277  {
5278  new_size.height = 1;
5279  }
5280 
5281  yetani->surface_resize_mutex_map[wl_surface].lock();
5282  {
5283  surface_extent.size_pixel = new_size;
5284  surfaceCalculateSize(yetani, wl_surface, new_size);
5285  }
5286  yetani->surface_resize_mutex_map[wl_surface].unlock();
5287 }
5288 
5289 // }}}
5290 // {{{ Wayland : Seat
5291 
5324 void Yetani::seatDestroy(struct wl_seat*& wl_seat
5325  ) noexcept
5326 {
5327  Yetani::Seat& seat = seat_map[wl_seat];
5328 
5329  if(seat.wl_keyboard != nullptr)
5330  {
5331  wl_keyboard_release(seat.wl_keyboard);
5332  seat.wl_keyboard = nullptr;
5333  }
5334 
5335  if(seat.wl_pointer != nullptr)
5336  {
5337  wl_pointer_release(seat.wl_pointer);
5338  seat.wl_pointer = nullptr;
5339  }
5340 
5341  if(seat.wl_touch != nullptr)
5342  {
5343  wl_touch_release(seat.wl_touch);
5344  seat.wl_touch = nullptr;
5345  }
5346 
5347  seat_map.erase(wl_seat);
5348 
5349  wl_seat_release(wl_seat);
5350 
5351  wl_seat = nullptr;
5352 }
5353 
5354 // }}}
5355 // {{{ Wayland : Seat : Keyboard
5356 
5430 int32_t Yetani::keyRepeatDelay() const noexcept
5431 {
5432  return keyboard.repeat_delay;
5433 }
5434 
5435 
5444 int32_t Yetani::keyRepeatRate() const noexcept
5445 {
5446  return 1000 / keyboard.repeat_rate;
5447 }
5448 
5449 
5453 void Yetani::keyboardDestroy(Yetani::Keyboard& keyboard
5454  ) noexcept
5455 {
5456  if(keyboard.keymap != nullptr)
5457  {
5458  munmap(keyboard.keymap, keyboard.keymap_size);
5459  }
5460 
5461  keyboard.wl_surface = nullptr;
5462  keyboard.event = nullptr;
5463  keyboard.modifier = { 0 };
5464  keyboard.repeat_rate = 0;
5465  keyboard.repeat_delay = {};
5466  keyboard.keymap = nullptr;
5467  keyboard.keymap_size = 0;
5468 }
5469 
5470 
5477 void Yetani::keyboardRepeat(Yetani::Keyboard& keyboard
5478  ) noexcept
5479 {
5480  auto now = std::chrono::steady_clock::now();
5481 
5482  for(auto& iter : keyboard.repeat_map)
5483  {
5484  Yetani::KeyRepeatData& key_repeat = iter.second;
5485 
5486  if(now >= key_repeat.trigger_time)
5487  {
5488  uint32_t key_code = iter.first;
5489 
5490  Yetani::Key key =
5491  { .time = key_repeat.base_time
5492  , .code = key_code
5493  , .state = Yetani::KeyState::Repeat
5494  };
5495 
5496  keyboard.event->on_key(key, keyboard.modifier);
5497 
5498  key_repeat.trigger_time = now
5499  + std::chrono::milliseconds(keyboard.repeat_rate)
5500  - (now - key_repeat.trigger_time)
5501  ;
5502  key_repeat.base_time += keyboard.repeat_rate;
5503  }
5504  }
5505 }
5506 
5507 
5515 void Yetani::keyboardRepeatAdd(Yetani::Keyboard& keyboard
5516  , uint32_t key_code
5517  , uint32_t time
5518  ) noexcept
5519 {
5520  auto trigger_time = std::chrono::steady_clock::now()
5521  + std::chrono::milliseconds(keyboard.repeat_delay)
5522  ;
5523 
5524  keyboard.repeat_map[key_code] =
5525  { .trigger_time = trigger_time
5526  , .base_time = time + keyboard.repeat_delay
5527  };
5528 }
5529 
5530 
5537 void Yetani::keyboardRepeatReleaseAll(Yetani::Keyboard& keyboard
5538  ) noexcept
5539 {
5540  while(keyboard.repeat_map.empty() == false)
5541  {
5542  auto iter = keyboard.repeat_map.begin();
5543 
5544  uint32_t key_code = iter->first;
5545 
5546  Yetani::Key key =
5547  { .time = 0
5548  , .code = key_code
5549  , .state = Yetani::KeyState::Released
5550  };
5551 
5552  keyboard.event->on_key(key, keyboard.modifier);
5553 
5554  keyboard.repeat_map.erase(iter);
5555  }
5556 }
5557 
5558 
5565 void Yetani::keyboardRepeatRemove(Yetani::Keyboard& keyboard
5566  , uint32_t key_code
5567  ) noexcept
5568 {
5569  keyboard.repeat_map.erase(key_code);
5570 }
5571 
5572 // }}}
5573 // {{{ Wayland : Seat : Pointer
5574 
5590 void Yetani::pointerClear(Yetani::Pointer& pointer
5591  ) noexcept
5592 {
5593  pointer.enter_surface = nullptr;
5594  pointer.enter_point = { 0, 0, 0 };
5595  pointer.leave_surface = nullptr;
5596  pointer.motion_point = { 0, 0, 0 };
5597  pointer.button_event_code = 0;
5598  pointer.button_is_pressed = false;
5599  pointer.button_time = 0;
5600  pointer.axis.time = 0;
5601  pointer.axis.type = Yetani::PointerAxisType::Unknown;
5602  pointer.axis.distance = 0;
5603  pointer.axis.source = Yetani::PointerAxisSource::Unknown;
5604  pointer.axis.steps = 0;
5605 }
5606 
5607 // }}}
5608 // {{{ Wayland : Surface
5609 
5647 void Yetani::surfaceCalculateSize(Yetani* yetani
5648  , struct wl_surface* wl_surface
5649  , const Yetani::SizePixel& size
5650  ) noexcept
5651 {
5652  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
5653  surface_size.width = size.width;
5654  surface_size.height = size.height;
5655  surface_size.stride = size.width * surface_size.bytes_per_pixel;
5656  surface_size.in_bytes = surface_size.stride * surface_size.height;
5657 
5658  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5659  surface_frame.width = size.width;
5660  surface_frame.height = size.height;
5661 }
5662 
5663 
5671 struct wl_surface* Yetani::surfaceCreate(Yetani* yetani
5672  , const wl_shm_format pixel_format
5673  , const Yetani::SizePixel& size
5674  , const bool attach_buffer
5675  , Yetani::Window::Memory& window_memory
5676  ) noexcept
5677 {
5678  struct wl_surface* wl_surface = wl_compositor_create_surface(yetani->compositor);
5679 
5680  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
5681  surface_size.pixel_format = pixel_format;
5682  surface_size.bytes_per_pixel = shmFormatBytesPerPixel(pixel_format);
5683 
5684  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5685  surface_frame.callback = nullptr;
5686  surface_frame.wl_surface = wl_surface;
5687  surface_frame.time_ms = 0;
5688 
5689  surfaceCalculateSize(yetani, wl_surface, size);
5690 
5691  surface_frame.buffer_next = bufferCreateAndRelease(yetani, surface_size, &window_memory);
5692 
5693  if(attach_buffer)
5694  {
5695  wl_surface_attach(surface_frame.wl_surface, surface_frame.buffer_next, 0, 0);
5696 
5697  surface_frame.callback = wl_surface_frame(wl_surface);
5698 
5699  wl_callback_add_listener(surface_frame.callback
5700  , &frame_callback_listener
5701  , &surface_frame
5702  );
5703 
5704  wl_surface_commit(wl_surface);
5705  }
5706 
5707  // A future configuration setting
5708  bool event_keyboard = true;
5709  if(event_keyboard)
5710  {
5711  yetani->keyboard.event_map[wl_surface] =
5712  { .on_enter = Lambda_DoNothing
5713  , .on_leave = Lambda_DoNothing
5714  , .on_key = LambdaKey_DoNothing
5715  };
5716  }
5717 
5718  // A future configuration setting
5719  bool event_pointer = true;
5720  if(event_pointer)
5721  {
5722  yetani->pointer.event_map[wl_surface] =
5723  { .on_axis = LambdaAxis_DoNothing
5724  , .on_axis_discrete = Lambda_DoNothing
5725  , .on_axis_source = Lambda_DoNothing
5726  , .on_axis_stop = Lambda_DoNothing
5727  , .on_button_mm = LambdaButtonMm_DoNothing
5728  , .on_button_percent = LambdaButtonPercent_DoNothing
5729  , .on_button_pixel = LambdaButtonPixel_DoNothing
5730  , .on_enter_mm = LambdaPointMm_DoNothing
5731  , .on_enter_percent = LambdaPointPercent_DoNothing
5732  , .on_enter_pixel = LambdaPointPixel_DoNothing
5733  , .on_leave = Lambda_DoNothing
5734  , .on_motion_mm = LambdaPointMm_DoNothing
5735  , .on_motion_percent = LambdaPointPercent_DoNothing
5736  , .on_motion_pixel = LambdaPointPixel_DoNothing
5737  };
5738  }
5739 
5740  yetani->surface_event_map[wl_surface] =
5741  { .on_size_mm_change = LambdaSizeMm_DoNothing
5742  , .on_size_percent_change = LambdaSizePercent_DoNothing
5743  , .on_size_pixel_change = LambdaSizePixel_DoNothing
5744  };
5745 
5746  wl_surface_add_listener(wl_surface
5747  , &surface_listener
5748  , yetani
5749  );
5750 
5751  return wl_surface;
5752 }
5753 
5754 
5760 void Yetani::surfaceDestroy(Yetani* yetani
5761  , struct wl_surface*& wl_surface
5762  ) noexcept
5763 {
5764  if(wl_surface == nullptr)
5765  {
5766  return;
5767  }
5768 
5769  if(yetani->surface_frame_map.contains(wl_surface))
5770  {
5771  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5772 
5773  if(surface_frame.callback != nullptr)
5774  {
5775  wl_callback_destroy(surface_frame.callback);
5776  surface_frame.callback = nullptr;
5777  }
5778 
5779  struct wl_buffer* wl_buffer = nullptr;
5780  wl_buffer = surface_frame.buffer_next.exchange(nullptr);
5781 
5782  if(wl_buffer != nullptr)
5783  {
5784  bufferDestroy(wl_buffer);
5785  }
5786  }
5787 
5788  if(yetani->keyboard.event_map.contains(wl_surface))
5789  {
5790  yetani->keyboard.event_map.erase(wl_surface);
5791  }
5792 
5793  if(yetani->pointer.event_map.contains(wl_surface))
5794  {
5795  yetani->pointer.event_map.erase(wl_surface);
5796  }
5797 
5798  yetani->surface_size_map.erase(wl_surface);
5799  yetani->surface_frame_map.erase(wl_surface);
5800  yetani->surface_event_map.erase(wl_surface);
5801 
5802  yetani->cursorDetach(wl_surface);
5803 
5804  wl_surface_destroy(wl_surface);
5805  wl_surface = nullptr;
5806 }
5807 
5808 // }}}
5809 // {{{ Wayland : Listener Handlers : Buffer
5810 
5823 void Yetani::handlerBufferRelease(void* //data
5824  , struct wl_buffer* wl_buffer
5825  ) noexcept
5826 {
5827  Yetani::bufferDestroy(wl_buffer);
5828 }
5829 
5830 // }}}
5831 // {{{ Wayland : Listener Handlers : Keyboard
5832 
5836 void Yetani::handlerKeyboardEnter(void* data
5837  , struct wl_keyboard* // wl_keyboard
5838  , uint32_t // serial
5839  , struct wl_surface* wl_surface
5840  , struct wl_array* key_array
5841  ) noexcept
5842 {
5843  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5844 
5845  if(keyboard.wl_surface != nullptr)
5846  {
5847  keyboardRepeatReleaseAll(keyboard);
5848 
5849  keyboard.event->on_leave();
5850  }
5851 
5852  keyboard.wl_surface = wl_surface;
5853 
5854  if(keyboard.event_map.contains(wl_surface))
5855  {
5856  keyboard.event = &(keyboard.event_map[wl_surface]);
5857  }
5858  else
5859  {
5860  keyboard.event = &(keyboard.event_map[nullptr]);
5861  }
5862 
5863  keyboard.event->on_enter();
5864 
5865  if(key_array->size > 0)
5866  {
5867  Yetani::Key key =
5868  { .time = 0
5869  , .code = 0
5870  , .state = Yetani::KeyState::Pressed
5871  };
5872 
5873  ZAKERO_YETANI__ARRAY_FOR_EACH(uint32_t*, key_iter, key_array)
5874  {
5875  key.code = *key_iter;
5876 
5877  keyboard.event->on_key(key, keyboard.modifier);
5878 
5879  keyboardRepeatAdd(keyboard, key.code, 0);
5880  }
5881  }
5882 }
5883 
5884 
5888 void Yetani::handlerKeyboardKey(void* data
5889  , struct wl_keyboard* // wl_keyboard
5890  , uint32_t // serial
5891  , uint32_t time
5892  , uint32_t key_code
5893  , uint32_t state
5894  ) noexcept
5895 {
5896  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5897 
5898  Yetani::Key key =
5899  { .time = time
5900  , .code = key_code
5901  , .state = (state == WL_KEYBOARD_KEY_STATE_PRESSED)
5902  ? Yetani::KeyState::Pressed
5903  : Yetani::KeyState::Released
5904  };
5905 
5906  keyboard.event->on_key(key, keyboard.modifier);
5907 
5908  if(key.state == Yetani::KeyState::Pressed
5909  && keyboard.repeat_rate > 0
5910  )
5911  {
5912  keyboardRepeatAdd(keyboard, key_code, time);
5913  }
5914  else if(key.state == Yetani::KeyState::Released)
5915  {
5916  keyboardRepeatRemove(keyboard, key_code);
5917  }
5918 }
5919 
5920 
5924 void Yetani::handlerKeyboardKeymap(void* data
5925  , struct wl_keyboard* // wl_keyboard
5926  , uint32_t format
5927  , int32_t fd
5928  , uint32_t size
5929  ) noexcept
5930 {
5931  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5932 
5933  if(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
5934  {
5935  if(keyboard.keymap != nullptr)
5936  {
5937  munmap(keyboard.keymap
5938  , keyboard.keymap_size
5939  );
5940  }
5941 
5942  keyboard.keymap = (char*)mmap(nullptr
5943  , size
5944  , PROT_READ
5945  , MAP_NORESERVE | MAP_PRIVATE
5946  , fd
5947  , 0
5948  );
5949  keyboard.keymap_size = size;
5950  }
5951  else // (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP)
5952  {
5953  if(keyboard.keymap != nullptr)
5954  {
5955  munmap(keyboard.keymap
5956  , keyboard.keymap_size
5957  );
5958 
5959  keyboard.keymap = nullptr;
5960  keyboard.keymap_size = 0;
5961  }
5962  }
5963 }
5964 
5965 
5969 void Yetani::handlerKeyboardLeave(void* data
5970  , struct wl_keyboard* // wl_keyboard
5971  , uint32_t // serial
5972  , struct wl_surface* wl_surface
5973  ) noexcept
5974 {
5975  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5976 
5977  if(keyboard.wl_surface == wl_surface)
5978  {
5979  keyboardRepeatReleaseAll(keyboard);
5980 
5981  keyboard.event->on_leave();
5982 
5983  keyboard.event = &(keyboard.event_map[nullptr]);
5984  keyboard.wl_surface = nullptr;
5985  }
5986 }
5987 
5988 
5992 void Yetani::handlerKeyboardModifiers(void* data
5993  , struct wl_keyboard* // wl_keyboard
5994  , uint32_t // serial
5995  , uint32_t mods_pressed
5996  , uint32_t mods_latched
5997  , uint32_t mods_locked
5998  , uint32_t group
5999  ) noexcept
6000 {
6001  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
6002 
6003  keyboard.modifier.pressed = mods_pressed;
6004  keyboard.modifier.latched = mods_latched;
6005  keyboard.modifier.locked = mods_locked;
6006  keyboard.modifier.group = group;
6007 }
6008 
6009 
6013 void Yetani::handlerKeyboardRepeatInfo(void* data
6014  , struct wl_keyboard* // wl_keyboard
6015  , int32_t rate
6016  , int32_t delay
6017  ) noexcept
6018 {
6019  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
6020 
6021  keyboard.repeat_delay = delay;
6022  keyboard.repeat_rate = 1000 / rate;
6023 }
6024 
6025 // }}}
6026 // {{{ Wayland : Listener Handlers : Output
6027 
6031 void Yetani::handlerOutputDone(void* data
6032  , struct wl_output* wl_output
6033  ) noexcept
6034 {
6035  Yetani* yetani = (Yetani*)data;
6036  Yetani::Output& output = yetani->output_data.output_map[wl_output];
6037  Yetani::Output& changes = yetani->output_changes_map[wl_output];
6038  Yetani::OutputId output_id = yetani->output_data.wloutput_to_outputid[wl_output];
6039 
6067  output = changes;
6068  output.pixels_per_mm_horizontal = output.width / float(output.physical_width_mm);
6069  output.pixels_per_mm_vertical = output.height / float(output.physical_height_mm);
6070 
6071  ZAKERO_YETANI__DEBUG << "\n" << to_string(output) << "\n";
6072 
6073  switch(yetani->output_state_map[wl_output])
6074  {
6075  case Yetani::OutputState::Done:
6076  // Do Nothing
6077  break;
6078 
6079  case Yetani::OutputState::Added:
6080  yetani->on_output_add(output_id);
6081  break;
6082 
6083  case Yetani::OutputState::Changed:
6084  yetani->on_output_change(output_id);
6085 
6086  for(auto wl_surface : yetani->output_notify_surface_vector)
6087  {
6088  outputNotifySurface(yetani, wl_output, wl_surface);
6089  }
6090 
6091  break;
6092  }
6093 
6094  yetani->output_state_map[wl_output] = Yetani::OutputState::Done;
6095 }
6096 
6097 
6101 void Yetani::handlerOutputGeometry(void* data
6102  , struct wl_output* wl_output
6103  , int32_t x
6104  , int32_t y
6105  , int32_t physical_width
6106  , int32_t physical_height
6107  , int32_t subpixel
6108  , const char* make
6109  , const char* model
6110  , int32_t transform
6111  ) noexcept
6112 {
6113  Yetani* yetani = (Yetani*)data;
6114  Yetani::Output& output_changes = yetani->output_changes_map[wl_output];
6115 
6116  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6117  {
6118  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6119  }
6120 
6121  output_changes.x = x;
6122  output_changes.y = y;
6123  output_changes.physical_width_mm = physical_width;
6124  output_changes.physical_height_mm = physical_height;
6125  output_changes.subpixel = subpixel;
6126  output_changes.make = std::string(make);
6127  output_changes.model = std::string(model);
6128  output_changes.transform = transform;
6129 }
6130 
6131 
6135 void Yetani::handlerOutputMode(void* data
6136  , struct wl_output* wl_output
6137  , uint32_t flags
6138  , int32_t width
6139  , int32_t height
6140  , int32_t refresh
6141  ) noexcept
6142 {
6143  Yetani* yetani = (Yetani*)data;
6144  Yetani::Output& output_changes = yetani->output_changes_map[wl_output];
6145 
6146  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6147  {
6148  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6149  }
6150 
6151  output_changes.flags = flags;
6152  output_changes.width = width;
6153  output_changes.height = height;
6154  output_changes.refresh_mHz = refresh;
6155 }
6156 
6157 
6161 void Yetani::handlerOutputScale(void* data
6162  , struct wl_output* wl_output
6163  , int32_t factor
6164  ) noexcept
6165 {
6166  Yetani* yetani = (Yetani*)data;
6167  Output& output_changes = yetani->output_changes_map[wl_output];
6168 
6169  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6170  {
6171  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6172  }
6173 
6174  output_changes.scale_factor = factor;
6175 }
6176 
6177 // }}}
6178 // {{{ Wayland : Listener Handlers : Pointer
6179 
6183 void Yetani::handlerPointerAxis(void* data
6184  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6185  , uint32_t time
6186  , uint32_t axis
6187  , wl_fixed_t value
6188  ) noexcept
6189 {
6190  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6191 
6192  pointer.axis.time = time;
6193  pointer.axis.distance = (float)wl_fixed_to_double(value);
6194 
6195  if(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
6196  {
6197  pointer.axis.type = Yetani::PointerAxisType::Horizontal;
6198  }
6199  else if(axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
6200  {
6201  pointer.axis.type = Yetani::PointerAxisType::Vertical;
6202  }
6203  else
6204  {
6205  pointer.axis.type = Yetani::PointerAxisType::Unknown;
6206  }
6207 }
6208 
6209 
6213 void Yetani::handlerPointerAxisDiscrete(void* data
6214  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6215  , uint32_t //axis ///< The axis
6216  , int32_t discrete
6217  ) noexcept
6218 {
6219  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6220 
6221  pointer.axis.steps = discrete;
6222 }
6223 
6224 
6228 void Yetani::handlerPointerAxisSource(void* data
6229  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6230  , uint32_t axis_source
6231  ) noexcept
6232 {
6233  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6234 
6235  switch(axis_source)
6236  {
6237  case WL_POINTER_AXIS_SOURCE_WHEEL:
6238  pointer.axis.source = Yetani::PointerAxisSource::Wheel;
6239  break;
6240 
6241  case WL_POINTER_AXIS_SOURCE_FINGER:
6242  pointer.axis.source = Yetani::PointerAxisSource::Finger;
6243  break;
6244 
6245  case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
6246  pointer.axis.source = Yetani::PointerAxisSource::Continuous;
6247  break;
6248 
6249  case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
6250  pointer.axis.source = Yetani::PointerAxisSource::Wheel_Tilt;
6251  break;
6252 
6253  default:
6254  pointer.axis.source = Yetani::PointerAxisSource::Unknown;
6255  }
6256 }
6257 
6258 
6262 void Yetani::handlerPointerAxisStop(void*
6263  , struct wl_pointer*
6264  , uint32_t
6265  , uint32_t
6266  ) noexcept
6267 {
6268  // --- Ignored ---
6269  //
6270  // Wayland documentation suggests that the "axis stop" can be used for
6271  // kinetic scrolling or to determine when one axis motions begins anew.
6272  //
6273  // This is not needed.
6274  // - For kinetic scrolling: Have the default scrolling be kinetic and
6275  // treat axis input as a new (or additive) velocity.
6276  // - For separation of axis motion, why? If there is a pause in the
6277  // motion, that reflects the user input.
6278 }
6279 
6280 
6284 void Yetani::handlerPointerButton(void* data
6285  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6286  , uint32_t //serial ///< The Event Id
6287  , uint32_t time
6288  , uint32_t button
6289  , uint32_t state
6290  ) noexcept
6291 {
6292  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6293 
6294  pointer.button.code = button;
6295  pointer.button_time = time;
6296 
6297  if(state == WL_POINTER_BUTTON_STATE_RELEASED)
6298  {
6299  pointer.button.state = Yetani::PointerButtonState::Released;
6300  }
6301  else if(state == WL_POINTER_BUTTON_STATE_PRESSED)
6302  {
6303  pointer.button.state = Yetani::PointerButtonState::Pressed;
6304  }
6305 }
6306 
6307 
6311 void Yetani::handlerPointerEnter(void* data
6312  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6313  , uint32_t serial
6314  , struct wl_surface* wl_surface
6315  , wl_fixed_t surface_x
6316  , wl_fixed_t surface_y
6317  ) noexcept
6318 {
6319  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6320 
6321  pointer.enter_serial = serial;
6322  pointer.enter_surface = wl_surface;
6323 
6324  pointer.enter_point =
6325  { .time = 0
6326  , .x = wl_fixed_to_int(surface_x)
6327  , .y = wl_fixed_to_int(surface_y)
6328  };
6329 }
6330 
6331 
6335 void Yetani::handlerPointerFrame(void* data
6336  , struct wl_pointer* wl_pointer
6337  ) noexcept
6338 {
6339  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6340  Yetani* yetani = pointer.yetani;
6341 
6342  if(pointer.enter_surface != nullptr)
6343  {
6344  if(pointer.wl_surface != nullptr)
6345  {
6346  yetani->cursorLeave(pointer.wl_surface);
6347  pointer.event_map[pointer.wl_surface].on_leave();
6348  }
6349 
6350  yetani->cursorEnter(wl_pointer
6351  , pointer.enter_serial
6352  , pointer.enter_surface
6353  );
6354 
6355  pointer.wl_surface = pointer.enter_surface;
6356  pointer.point_pixel = pointer.enter_point;
6357 
6358  if(pointer.event_map.contains(pointer.wl_surface))
6359  {
6360  pointer.event = &(pointer.event_map[pointer.wl_surface]);
6361  }
6362  else
6363  {
6364  pointer.event = &(pointer.event_map[nullptr]);
6365  }
6366 
6367  yetani->convertPixel(pointer.enter_surface
6368  , pointer.point_pixel.x , pointer.point_pixel.y
6369  , pointer.point_mm.x , pointer.point_mm.y
6370  , pointer.point_percent.x, pointer.point_percent.y
6371  );
6372 
6373  pointer.event->on_enter_pixel(pointer.point_pixel
6374  , yetani->keyboard.modifier
6375  );
6376  pointer.event->on_enter_mm(pointer.point_mm
6377  , yetani->keyboard.modifier
6378  );
6379  pointer.event->on_enter_percent(pointer.point_percent
6380  , yetani->keyboard.modifier
6381  );
6382  }
6383 
6384  if((pointer.motion_point.time != 0)
6385  && (pointer.wl_surface != nullptr)
6386  )
6387  {
6388  pointer.point_pixel = pointer.motion_point;
6389 
6390  yetani->convertPixel(pointer.wl_surface
6391  , pointer.point_pixel.x , pointer.point_pixel.y
6392  , pointer.point_mm.x , pointer.point_mm.y
6393  , pointer.point_percent.x, pointer.point_percent.y
6394  );
6395  pointer.point_mm.time = pointer.point_pixel.time;
6396  pointer.point_percent.time = pointer.point_pixel.time;
6397 
6398  pointer.event->on_motion_pixel(pointer.point_pixel
6399  , yetani->keyboard.modifier
6400  );
6401  pointer.event->on_motion_mm(pointer.point_mm
6402  , yetani->keyboard.modifier
6403  );
6404  pointer.event->on_motion_percent(pointer.point_percent
6405  , yetani->keyboard.modifier
6406  );
6407  }
6408 
6409  if((pointer.button_time != 0)
6410  && (pointer.wl_surface != nullptr)
6411  )
6412  {
6413  pointer.point_mm.time = pointer.button_time;
6414  pointer.point_percent.time = pointer.button_time;
6415  pointer.point_pixel.time = pointer.button_time;
6416 
6417  pointer.event->on_button_pixel(pointer.button
6418  , pointer.point_pixel
6419  , yetani->keyboard.modifier
6420  );
6421  pointer.event->on_button_mm(pointer.button
6422  , pointer.point_mm
6423  , yetani->keyboard.modifier
6424  );
6425  pointer.event->on_button_percent(pointer.button
6426  , pointer.point_percent
6427  , yetani->keyboard.modifier
6428  );
6429  }
6430 
6431  if((pointer.axis.time != 0)
6432  && (pointer.wl_surface != nullptr)
6433  )
6434  {
6435  pointer.event->on_axis(pointer.axis
6436  , yetani->keyboard.modifier
6437  );
6438  }
6439 
6440  if((pointer.leave_surface != nullptr)
6441  && (pointer.leave_surface == pointer.wl_surface)
6442  )
6443  {
6444  yetani->cursorLeave(pointer.leave_surface);
6445 
6446  pointer.event->on_leave();
6447 
6448  pointer.event = &(pointer.event_map[nullptr]);
6449  pointer.wl_surface = nullptr;
6450  }
6451 
6452  pointerClear(pointer);
6453 }
6454 
6455 
6459 void Yetani::handlerPointerLeave(void* data
6460  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6461  , uint32_t //serial ///< The Event Id
6462  , struct wl_surface* wl_surface
6463  ) noexcept
6464 {
6465  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6466 
6467  pointer.leave_surface = wl_surface;
6468 }
6469 
6470 
6474 void Yetani::handlerPointerMotion(void* data
6475  , struct wl_pointer* //wl_pointer ///< The Wayland Pointer
6476  , uint32_t time
6477  , wl_fixed_t surface_x
6478  , wl_fixed_t surface_y
6479  ) noexcept
6480 {
6481  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6482 
6483  pointer.motion_point =
6484  { .time = time
6485  , .x = wl_fixed_to_int(surface_x)
6486  , .y = wl_fixed_to_int(surface_y)
6487  };
6488 }
6489 
6490 // }}}
6491 // {{{ Wayland : Listener Handlers : Registry
6492 
6496 void Yetani::handlerRegistryGlobal(void* data
6497  , struct wl_registry* registry
6498  , uint32_t id
6499  , const char* interface
6500  , uint32_t version
6501  ) noexcept
6502 {
6503  Yetani* yetani = (Yetani*)data;
6504 
6505  std::string_view interface_name(interface);
6506  ZAKERO_YETANI__DEBUG_VAR(interface_name);
6507 
6508  if(interface_name == wl_compositor_interface.name)
6509  {
6510  yetani->compositor = (struct wl_compositor*)
6511  wl_registry_bind(registry
6512  , id
6513  , &wl_compositor_interface
6514  , 1
6515  );
6516 
6517  return;
6518  }
6519 
6520  if(interface_name == wl_output_interface.name)
6521  {
6522  struct wl_output* wl_output = (struct wl_output*)wl_registry_bind(registry
6523  , id
6524  , &wl_output_interface
6525  , 2
6526  );
6527 
6528  yetani->output_data.wloutput_to_outputid[wl_output] = id;
6529  yetani->output_data.outputid_to_wloutput[id] = wl_output;
6530  yetani->output_data.output_map[wl_output] = {};
6531  yetani->output_changes_map[wl_output] = {};
6532  yetani->output_state_map[wl_output] = Yetani::OutputState::Added;
6533 
6534  wl_output_add_listener(wl_output
6535  , &Yetani::output_listener
6536  , yetani
6537  );
6538 
6539  return;
6540  }
6541 
6542  if(interface_name == wl_seat_interface.name)
6543  {
6544  yetani->seat = (struct wl_seat*)
6545  wl_registry_bind(registry
6546  , id
6547  , &wl_seat_interface
6548  , version
6549  );
6550 
6551  yetani->id_to_seat[id] = yetani->seat;
6552 
6553  wl_seat_add_listener(yetani->seat
6554  , &yetani->seat_listener
6555  , yetani
6556  );
6557 
6558  return;
6559  }
6560 
6561  if(interface_name == wl_shm_interface.name)
6562  {
6563  yetani->shm = (struct wl_shm*)
6564  wl_registry_bind(registry
6565  , id
6566  , &wl_shm_interface
6567  , version
6568  );
6569 
6570  wl_shm_add_listener(yetani->shm
6571  , &yetani->shm_listener
6572  , yetani
6573  );
6574 
6575  return;
6576  }
6577 
6578  if(interface_name == xdg_wm_base_interface.name)
6579  {
6580  yetani->xdg_wm_base = (struct xdg_wm_base*)
6581  wl_registry_bind(registry
6582  , id
6583  , &xdg_wm_base_interface
6584  , 1
6585  );
6586 
6587  xdg_wm_base_add_listener(yetani->xdg_wm_base
6588  , &yetani->xdg_wm_base_listener
6589  , yetani
6590  );
6591  }
6592 
6593  if(interface_name == zxdg_decoration_manager_v1_interface.name)
6594  {
6595  yetani->decoration_manager = (struct zxdg_decoration_manager_v1*)
6596  wl_registry_bind(registry
6597  , id
6598  , &zxdg_decoration_manager_v1_interface
6599  , 1
6600  );
6601  ZAKERO_YETANI__DEBUG << "--- Using UNSTABLE Decoration Manager ---\n";
6602  }
6603 }
6604 
6605 
6609 void Yetani::handlerRegistryRemove(void* data
6610  , struct wl_registry* //registry ///< The registry object
6611  , uint32_t id
6612  ) noexcept
6613 {
6614  Yetani* yetani = (Yetani*)data;
6615 
6616  printf("Got a registry remove event for id %d\n", id);
6617 
6618  // Output
6619  {
6620  std::lock_guard<std::mutex> lock(yetani->output_data.mutex);
6621 
6622  if(yetani->output_data.outputid_to_wloutput.contains(id))
6623  {
6624  struct wl_output* wl_output = yetani->output_data.outputid_to_wloutput[id];
6625 
6626  yetani->output_data.outputid_to_wloutput.erase(id);
6627  yetani->output_data.wloutput_to_outputid.erase(wl_output);
6628 
6629  yetani->output_changes_map.erase(wl_output);
6630  yetani->output_state_map.erase(wl_output);
6631 
6632  yetani->on_output_remove(id);
6633  yetani->output_data.output_map.erase(wl_output);
6634 
6635  return;
6636  }
6637  }
6638 
6639  // Seat
6640  {
6641  if(yetani->id_to_seat.contains(id))
6642  {
6643  struct wl_seat* wl_seat = yetani->id_to_seat[id];
6644 
6645  yetani->seatDestroy(wl_seat);
6646 
6647  yetani->id_to_seat.erase(id);
6648  }
6649  }
6650 }
6651 
6652 // }}}
6653 // {{{ Wayland : Listener Handlers : Seat
6654 
6662 void Yetani::handlerSeatCapabilities(void* data
6663  , struct wl_seat* wl_seat
6664  , uint32_t capabilities
6665  ) noexcept
6666 {
6667  ZAKERO_YETANI__DEBUG_VAR((uint64_t)wl_seat);
6668 
6669  Yetani* yetani = (Yetani*)data;
6670  Yetani::Seat& seat = yetani->seat_map[wl_seat];
6671 
6672  seat.version = wl_seat_get_version(wl_seat);
6673 
6674  if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD)
6675  {
6676  ZAKERO_YETANI__DEBUG << "-- Got a keyboard device --\n";
6677 
6678  yetani->keyboard.event_map[nullptr] =
6679  { .on_enter = Lambda_DoNothing
6680  , .on_leave = Lambda_DoNothing
6681  , .on_key = LambdaKey_DoNothing
6682  };
6683 
6684  yetani->keyboard.event = &(yetani->keyboard.event_map[nullptr]);
6685 
6686  seat.wl_keyboard = wl_seat_get_keyboard(wl_seat);
6687 
6688  wl_keyboard_add_listener(seat.wl_keyboard
6689  , &Yetani::keyboard_listener
6690  , &yetani->keyboard
6691  );
6692  }
6693 
6694  if(capabilities & WL_SEAT_CAPABILITY_POINTER)
6695  {
6696  ZAKERO_YETANI__DEBUG << "-- Got a pointer device --\n";
6697 
6698  yetani->pointer.yetani = yetani;
6699 
6700  yetani->pointer.event_map[nullptr] =
6701  { .on_axis = LambdaAxis_DoNothing
6702  , .on_axis_discrete = Lambda_DoNothing
6703  , .on_axis_source = Lambda_DoNothing
6704  , .on_axis_stop = Lambda_DoNothing
6705  , .on_button_mm = LambdaButtonMm_DoNothing
6706  , .on_button_percent = LambdaButtonPercent_DoNothing
6707  , .on_button_pixel = LambdaButtonPixel_DoNothing
6708  , .on_enter_mm = LambdaPointMm_DoNothing
6709  , .on_enter_percent = LambdaPointPercent_DoNothing
6710  , .on_enter_pixel = LambdaPointPixel_DoNothing
6711  , .on_leave = Lambda_DoNothing
6712  , .on_motion_mm = LambdaPointMm_DoNothing
6713  , .on_motion_percent = LambdaPointPercent_DoNothing
6714  , .on_motion_pixel = LambdaPointPixel_DoNothing
6715  };
6716 
6717  yetani->pointer.event = &(yetani->pointer.event_map[nullptr]);
6718 
6719  seat.wl_pointer = wl_seat_get_pointer(wl_seat);
6720 
6721  wl_pointer_add_listener(seat.wl_pointer
6722  , &Yetani::pointer_listener
6723  , &yetani->pointer
6724  );
6725  }
6726 
6727  if(capabilities & WL_SEAT_CAPABILITY_TOUCH)
6728  {
6729  ZAKERO_YETANI__DEBUG << "-- Got a touch device --\n";
6730  seat.wl_touch = wl_seat_get_touch(wl_seat);
6731 
6732  //wl_touch_add_listener(seat.wl_touch
6733  // , &Yetani::touch_listener
6734  // , data
6735  // );
6736  }
6737 }
6738 
6739 
6743 void Yetani::handlerSeatName(void* data
6744  , struct wl_seat* wl_seat
6745  , const char* name
6746  ) noexcept
6747 {
6748  ZAKERO_YETANI__DEBUG_VAR((uint64_t)wl_seat);
6749  ZAKERO_YETANI__DEBUG_VAR(name);
6750 
6751  Yetani* yetani = (Yetani*)data;
6752 
6753  yetani->seat_map[wl_seat].name = name;
6754 }
6755 
6756 // }}}
6757 // {{{ Wayland : Listener Handlers : SHM
6758 
6762 void Yetani::handlerShmFormat(void* data
6763  , struct wl_shm* /* Unused */
6764  , uint32_t value
6765  ) noexcept
6766 {
6767  Yetani* yetani = (Yetani*)data;
6768 
6769  wl_shm_format format = (wl_shm_format)value;
6770 
6771  if(vectorContains(yetani->shm_format_vector, format))
6772  {
6773  return;
6774  }
6775 
6776  yetani->shm_format_vector.push_back(format);
6777 }
6778 
6779 // }}}
6780 // {{{ Wayland : Listener Handlers : Surface
6781 
6785 void Yetani::handlerSurfaceEnter(void* data
6786  , struct wl_surface* wl_surface
6787  , struct wl_output* wl_output
6788  ) noexcept
6789 {
6790  //ZAKERO_YETANI__DEBUG << "-------------------------------------------\n";
6791  //ZAKERO_YETANI__DEBUG_VAR(data);
6792  //ZAKERO_YETANI__DEBUG_VAR(wl_surface);
6793  //ZAKERO_YETANI__DEBUG_VAR(wl_output);
6794 
6795  Yetani* yetani = (Yetani*)data;
6796  Yetani::OutputData& output_data = yetani->output_data;
6797 
6798  output_data.mutex.lock();
6799  output_data.surface_output_map[wl_surface].push_back(wl_output);
6800  output_data.mutex.unlock();
6801 }
6802 
6803 
6807 void Yetani::handlerSurfaceLeave(void* data
6808  , struct wl_surface* wl_surface
6809  , struct wl_output* wl_output
6810  ) noexcept
6811 {
6812  //ZAKERO_YETANI__DEBUG << "-------------------------------------------\n";
6813  //ZAKERO_YETANI__DEBUG_VAR(data);
6814  //ZAKERO_YETANI__DEBUG_VAR(wl_surface);
6815  //ZAKERO_YETANI__DEBUG_VAR(wl_output);
6816 
6817  Yetani* yetani = (Yetani*)data;
6818 
6819  Yetani::OutputData& output_data = yetani->output_data;
6820  std::lock_guard<std::mutex> lock(output_data.mutex);
6821 
6822  Yetani::VectorWlOutput& output_vector = output_data.surface_output_map[wl_surface];
6823 
6824  // Save the current wl_output device id
6825  struct wl_output* current_output = output_vector.front();
6826 
6827  // Remove the wl_output device id
6828  zakero::vectorErase(output_vector, wl_output);
6829 
6830  // Check if the current wl_output device id was removed
6831  if(current_output == output_vector.front())
6832  {
6833  // Current wl_output device was not removed
6834  // so nothing to do.
6835 
6836  return;
6837  }
6838 
6839  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
6840 
6841  if(surface_extent.preferred_unit == Yetani::SizeUnit::Pixel)
6842  {
6843  return;
6844  }
6845 
6846  // Convert the relative window size from the old wl_output device
6847  // to the new wl_output device.
6848 
6849  current_output = output_vector.front();
6850 
6851  Yetani::Output& output = output_data.output_map.at(current_output);
6852  Yetani::SizePixel new_size;
6853 
6854  if(surface_extent.preferred_unit == Yetani::SizeUnit::Millimeter)
6855  {
6856  auto p = yetani->convertMmToPixel(output
6857  , surface_extent.size_mm.width
6858  , surface_extent.size_mm.height
6859  );
6860 
6861  new_size = { p.first, p.second };
6862  }
6863  else // if(surface_extent.preferred_unit == Yetani::SizeUnit::Percent)
6864  {
6865  auto p = yetani->convertPercentToPixel(output
6866  , surface_extent.size_percent.width
6867  , surface_extent.size_percent.height
6868  );
6869 
6870  new_size = { p.first, p.second };
6871  }
6872 
6873  if(new_size.width <= 0)
6874  {
6875  new_size.width = 1;
6876  }
6877 
6878  if(new_size.height <= 0)
6879  {
6880  new_size.height = 1;
6881  }
6882 
6883  if((new_size.width != surface_extent.size_pixel.width)
6884  && (new_size.height != surface_extent.size_pixel.height)
6885  )
6886  {
6887  yetani->surface_resize_mutex_map[wl_surface].lock();
6888  {
6889  XdgSurface& surface = yetani->xdg_surface_map[wl_surface];
6890 
6891  surface_extent.size_pixel = new_size;
6892  surfaceCalculateSize(surface.yetani, surface.wl_surface, new_size);
6893  }
6894  yetani->surface_resize_mutex_map[wl_surface].unlock();
6895 
6896  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
6897  event.on_size_pixel_change(surface_extent.size_pixel);
6898  }
6899 }
6900 
6901 // }}}
6902 // {{{ Wayland : Listener Handlers : SwapBuffers
6903 
6907 void Yetani::handlerSwapBuffers(void* data
6908  , struct wl_callback* callback
6909  , uint32_t time_ms
6910  ) noexcept
6911 {
6912  Yetani::SurfaceFrame* surface_frame = (Yetani::SurfaceFrame*)data;
6913 
6914  wl_callback_destroy(callback);
6915 
6916  surface_frame->callback = wl_surface_frame(surface_frame->wl_surface);
6917 
6918  wl_callback_add_listener(surface_frame->callback
6919  , &frame_callback_listener
6920  , data
6921  );
6922 
6923  struct wl_buffer* wl_buffer = surface_frame->buffer_next.exchange(nullptr);
6924  if(wl_buffer != nullptr)
6925  {
6926  surface_frame->time_ms = time_ms;
6927 
6928  wl_surface_attach(surface_frame->wl_surface, wl_buffer, 0, 0);
6929 
6930  wl_surface_damage(surface_frame->wl_surface
6931  , 0, 0
6932  , surface_frame->width, surface_frame->height
6933  );
6934  }
6935 
6936  wl_surface_commit(surface_frame->wl_surface);
6937 }
6938 
6939 // }}}
6940 // {{{ Wayland : Listener Handlers (Unstable)
6941 
6942 
6943 // }}}
6944 // {{{ XDG
6945 
6958 Yetani::WindowMode Yetani::toWindowMode(const Yetani::XdgState state
6959  ) noexcept
6960 {
6961  switch(state)
6962  {
6963  case Yetani::XdgState::Toplevel_Window_Fullscreen:
6964  return Yetani::WindowMode::Fullscreen;
6965 
6966  case Yetani::XdgState::Toplevel_Window_Maximized:
6967  return Yetani::WindowMode::Maximized;
6968 
6969  default:
6970  case Yetani::XdgState::Toplevel_Window_Normal:
6972  }
6973 }
6974 
6975 
6981 Yetani::XdgState Yetani::toXdgState(const Yetani::WindowMode window_mode
6982  ) noexcept
6983 {
6984  switch(window_mode)
6985  {
6986  case Yetani::WindowMode::Fullscreen:
6987  return Yetani::XdgState::Toplevel_Window_Fullscreen;
6988 
6989  case Yetani::WindowMode::Maximized:
6990  return Yetani::XdgState::Toplevel_Window_Maximized;
6991 
6992  default:
6994  return Yetani::XdgState::Toplevel_Window_Normal;
6995  }
6996 }
6997 
6998 // }}}
6999 // {{{ XDG : Surface
7000 
7021 struct xdg_surface* Yetani::xdgSurfaceCreate(struct wl_surface* wl_surface
7022  ) noexcept
7023 {
7024  XdgSurface& surface = xdg_surface_map[wl_surface];
7025 
7026  surface.yetani = this;
7027  surface.wl_surface = wl_surface;
7028 
7029  surface_extent_mutex.lock();
7030  {
7031  Yetani::SurfaceExtent& surface_extent = surface_extent_map[wl_surface];
7032 
7033  surface_extent.preferred_unit = Yetani::SizeUnit::Pixel;
7034  surface_extent.preferred_mm = { 160, 90 }; // 16:9 * 10mm
7035  surface_extent.preferred_percent = { 0.32, 0.18 }; // 16:9 * 0.02
7036  surface_extent.size_mm = { 160, 90 }; // 16:9 + 10mm
7037  surface_extent.size_percent = { 0.32, 0.18 }; // 16:9 * 0.02
7038  surface_extent.size_pixel = { 800, 450 }; // 16:9 * 50 pixels
7039  surface_extent.size_pixel_max = { 0, 0 }; // No maximum size
7040  surface_extent.size_pixel_min = { 0, 0 }; // No minimum size
7041  }
7042  surface_extent_mutex.unlock();
7043 
7044  output_notify_surface_vector.push_back(wl_surface);
7045 
7046  struct xdg_surface* xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base
7047  , wl_surface
7048  );
7049 
7050  xdg_state_change_mutex.lock();
7051  {
7052  xdg_state_change_map[xdg_surface] = {};
7053  }
7054  xdg_state_change_mutex.unlock();
7055 
7056  xdg_surface_add_listener(xdg_surface
7057  , &xdg_surface_listener
7058  , &surface
7059  );
7060 
7061  return xdg_surface;
7062 }
7063 
7064 
7073 void Yetani::xdgSurfaceDestroy(struct wl_surface* wl_surface
7074  , struct xdg_surface*& xdg_surface
7075  ) noexcept
7076 {
7077  if(xdg_surface)
7078  {
7079  xdg_surface_destroy(xdg_surface);
7080  }
7081 
7082  zakero::vectorErase(output_notify_surface_vector, wl_surface);
7083 
7084  if(xdg_surface_map.contains(wl_surface))
7085  {
7086  xdg_surface_map.erase(wl_surface);
7087  }
7088 
7089  xdg_state_change_mutex.lock();
7090  {
7091  if(xdg_state_change_map.contains(xdg_surface))
7092  {
7093  xdg_state_change_map.erase(xdg_surface);
7094  }
7095  }
7096  xdg_state_change_mutex.unlock();
7097 
7098  surface_extent_mutex.lock();
7099  {
7100  if(surface_extent_map.contains(wl_surface))
7101  {
7102  surface_extent_map.erase(wl_surface);
7103  }
7104  }
7105  surface_extent_mutex.unlock();
7106 
7107  xdg_surface = nullptr;
7108 }
7109 
7110 
7114 void Yetani::xdgSurfaceSetExtent(struct wl_surface* wl_surface
7115  , const Yetani::SizeUnit& size_unit
7116  , const Yetani::SizeMm& size_mm
7117  , const Yetani::SizePercent& size_percent
7118  , const Yetani::SizePixel& size_pixel
7119  ) noexcept
7120 {
7121  Yetani::SurfaceExtent& surface_extent = surface_extent_map[wl_surface];
7122 
7123  surface_extent.preferred_unit = size_unit;
7124  surface_extent.preferred_mm = size_mm;
7125  surface_extent.preferred_percent = size_percent;
7126  surface_extent.size_mm = size_mm;
7127  surface_extent.size_percent = size_percent;
7128  surface_extent.size_pixel = size_pixel;
7129  surface_extent.size_pixel_max = { 0, 0 };
7130  surface_extent.size_pixel_min = { 0, 0 };
7131 }
7132 
7133 // }}}
7134 // {{{ XDG : Toplevel
7135 
7174 struct xdg_toplevel* Yetani::xdgToplevelCreate(struct xdg_surface* xdg_surface
7175  ) noexcept
7176 {
7177  Yetani::XdgToplevel& toplevel = xdg_toplevel_map[xdg_surface];
7178 
7179  toplevel.close_request_lambda = Lambda_DoNothing;
7180  toplevel.state_change = &(xdg_state_change_map[xdg_surface]);
7181  toplevel.is_active = false;
7182  toplevel.window_state = Yetani::XdgState::Toplevel_Window_Normal;
7183  toplevel.is_active_lambda = LambdaBool_DoNothing;
7184  toplevel.window_state_lambda = LambdaWindowMode_DoNothing;
7185  toplevel.previous_size = { 0, 0 };
7186  toplevel.xdg_toplevel = nullptr;
7187 
7193  toplevel.state_change->push_back(Yetani::XdgState::Toplevel_Attach_Buffer);
7194 
7195  struct xdg_toplevel* xdg_toplevel = nullptr;
7196 
7197  xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
7198  toplevel.xdg_toplevel = xdg_toplevel;
7199 
7200  xdg_toplevel_add_listener(xdg_toplevel
7201  , &xdg_toplevel_listener
7202  , &toplevel
7203  );
7204 
7205  return xdg_toplevel;
7206 }
7207 
7208 
7215 void Yetani::xdgToplevelDestroy(struct xdg_surface* xdg_surface
7216  , struct xdg_toplevel*& xdg_toplevel
7217  ) noexcept
7218 {
7219  if(xdg_toplevel != nullptr)
7220  {
7221  xdg_toplevel_destroy(xdg_toplevel);
7222  }
7223 
7224  if(xdg_toplevel_map.contains(xdg_surface))
7225  {
7226  XdgToplevel& toplevel = xdg_toplevel_map[xdg_surface];
7227 
7228  toplevel.close_request_lambda = nullptr;
7229  toplevel.state_change = nullptr;
7230  toplevel.window_state = Yetani::XdgState::Unknown;
7231  toplevel.is_active = false;
7232  toplevel.is_active_lambda = nullptr;
7233  toplevel.window_state_lambda = nullptr;
7234 
7235  xdg_toplevel_map.erase(xdg_surface);
7236  }
7237 
7238  xdg_toplevel = nullptr;
7239 }
7240 
7241 
7251 void Yetani::xdgToplevelSizeChange(Yetani* yetani
7252  , struct wl_surface* wl_surface
7253  , const Yetani::SizePixel& size_pixel
7254  ) noexcept
7255 {
7256  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7257  Yetani::SizePixel new_size = surface_extent.size_pixel;
7258 
7259  if(((surface_extent.size_pixel_min.width == 0) || (size_pixel.width >= surface_extent.size_pixel_min.width))
7260  && ((surface_extent.size_pixel_max.width == 0) || (size_pixel.width <= surface_extent.size_pixel_max.width))
7261  )
7262  {
7263  new_size.width = size_pixel.width;
7264  }
7265 
7266  if(((surface_extent.size_pixel_min.height == 0) || (size_pixel.height >= surface_extent.size_pixel_min.height))
7267  && ((surface_extent.size_pixel_max.height == 0) || (size_pixel.height <= surface_extent.size_pixel_max.height))
7268  )
7269  {
7270  new_size.height = size_pixel.height;
7271  }
7272 
7273  if((new_size.width == surface_extent.size_pixel.width)
7274  && (new_size.height == surface_extent.size_pixel.height)
7275  )
7276  {
7277  return;
7278  }
7279 
7280  // Calculate Sizes
7281  Yetani::SizeMm size_mm;
7282  Yetani::SizePercent size_percent;
7283  yetani->convertPixel(wl_surface
7284  , size_pixel.width , size_pixel.height
7285  , size_mm.width , size_mm.height
7286  , size_percent.width, size_percent.height
7287  );
7288 
7289  yetani->surface_resize_mutex_map[wl_surface].lock();
7290  {
7291  surface_extent.size_pixel = new_size;
7292  surfaceCalculateSize(yetani, wl_surface, new_size);
7293  }
7294  yetani->surface_resize_mutex_map[wl_surface].unlock();
7295 
7296  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
7297  event.on_size_pixel_change(surface_extent.size_pixel);
7298  event.on_size_mm_change(surface_extent.size_mm);
7299  event.on_size_percent_change(surface_extent.size_percent);
7300 }
7301 
7302 
7306 void Yetani::xdgToplevelSizeMinMaxChange(Yetani* yetani
7307  , struct xdg_toplevel* xdg_toplevel
7308  , struct wl_surface* wl_surface
7309  , const Yetani::SizePixel& size_pixel_min
7310  , const Yetani::SizePixel& size_pixel_max
7311  ) noexcept
7312 {
7313  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7314 
7315  Yetani::SizePixel size_pixel = surface_extent.size_pixel;
7316  bool need_to_resize = false;
7317 
7318  if(size_pixel_max.width > 0
7319  && size_pixel_max.width < surface_extent.size_pixel.width
7320  )
7321  {
7322  need_to_resize = true;
7323  size_pixel.width = size_pixel_max.width;
7324  }
7325 
7326  if(size_pixel_max.height > 0
7327  && size_pixel_max.height < surface_extent.size_pixel.height
7328  )
7329  {
7330  need_to_resize = true;
7331  size_pixel.height = size_pixel_max.height;
7332  }
7333 
7334  if(size_pixel_min.width > 0
7335  && size_pixel_min.width > surface_extent.size_pixel.width
7336  )
7337  {
7338  need_to_resize = true;
7339  size_pixel.width = size_pixel_min.width;
7340  }
7341 
7342  if(size_pixel_min.height > 0
7343  && size_pixel_min.height > surface_extent.size_pixel.height
7344  )
7345  {
7346  need_to_resize = true;
7347  size_pixel.height = size_pixel_min.height;
7348  }
7349 
7350  if(need_to_resize)
7351  {
7352  xdg_toplevel_set_max_size(xdg_toplevel, 0, 0);
7353  xdg_toplevel_set_min_size(xdg_toplevel, 0, 0);
7354 
7355  yetani->surface_resize_mutex_map[wl_surface].lock();
7356  {
7357  surface_extent.size_pixel = size_pixel;
7358  surfaceCalculateSize(yetani, wl_surface, size_pixel);
7359  }
7360  yetani->surface_resize_mutex_map[wl_surface].unlock();
7361  }
7362 
7363  xdg_toplevel_set_min_size(xdg_toplevel
7364  , size_pixel_min.width
7365  , size_pixel_min.height
7366  );
7367 
7368  xdg_toplevel_set_max_size(xdg_toplevel
7369  , size_pixel_max.width
7370  , size_pixel_max.height
7371  );
7372 
7373  surface_extent.size_pixel_min = size_pixel_min;
7374  surface_extent.size_pixel_max = size_pixel_max;
7375 }
7376 
7377 
7381 void Yetani::xdgToplevelWindowChange(Yetani* yetani
7382  , struct wl_surface* wl_surface
7383  , Yetani::XdgToplevel& toplevel
7384  , const Yetani::XdgState window_state
7385  , const Yetani::SizePixel& size_pixel
7386  ) noexcept
7387 {
7388  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7389  Yetani::SizePixel new_size(1, 1);
7390 
7391  toplevel.window_state = window_state;
7392 
7393  if((toplevel.window_state == Yetani::XdgState::Toplevel_Window_Fullscreen)
7394  || (toplevel.window_state == Yetani::XdgState::Toplevel_Window_Maximized)
7395  )
7396  {
7397  if(toplevel.previous_size.width == 0)
7398  {
7399  xdg_toplevel_set_max_size(toplevel.xdg_toplevel, 0, 0);
7400  xdg_toplevel_set_min_size(toplevel.xdg_toplevel, 0, 0);
7401 
7402  toplevel.previous_size = surface_extent.size_pixel;
7403  }
7404 
7405  if((size_pixel.width != 0)
7406  && (size_pixel.height != 0)
7407  )
7408  {
7409  new_size = size_pixel;
7410  }
7411  }
7412  else if(toplevel.window_state == Yetani::XdgState::Toplevel_Window_Normal)
7413  {
7414  xdg_toplevel_set_max_size(toplevel.xdg_toplevel
7415  , surface_extent.size_pixel_max.width
7416  , surface_extent.size_pixel_max.height
7417  );
7418 
7419  xdg_toplevel_set_min_size(toplevel.xdg_toplevel
7420  , surface_extent.size_pixel_min.width
7421  , surface_extent.size_pixel_min.height
7422  );
7423 
7424  new_size = toplevel.previous_size;
7425  toplevel.previous_size.width = 0;
7426  }
7427 
7428  if(new_size == surface_extent.size_pixel)
7429  {
7430  return;
7431  }
7432 
7433  // Calculate Size
7434  Yetani::SizeMm size_mm;
7435  Yetani::SizePercent size_percent;
7436  yetani->convertPixel(wl_surface
7437  , size_pixel.width , size_pixel.height
7438  , size_mm.width , size_mm.height
7439  , size_percent.width, size_percent.height
7440  );
7441 
7442  yetani->surface_resize_mutex_map[wl_surface].lock();
7443  {
7444  surface_extent.size_mm = size_mm;
7445  surface_extent.size_percent = size_percent;
7446  surface_extent.size_pixel = new_size;
7447  surfaceCalculateSize(yetani, wl_surface, new_size);
7448  }
7449  yetani->surface_resize_mutex_map[wl_surface].unlock();
7450 
7451  toplevel.window_state_lambda(Yetani::toWindowMode(toplevel.window_state));
7452 
7453  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
7454  event.on_size_pixel_change(surface_extent.size_pixel);
7455  event.on_size_mm_change(surface_extent.size_mm);
7456  event.on_size_percent_change(surface_extent.size_percent);
7457 }
7458 
7459 // }}}
7460 // {{{ XDG : Decoration (Unstable)
7461 
7485 struct zxdg_toplevel_decoration_v1* Yetani::xdgDecorationCreate(struct xdg_surface* xdg_surface
7486  , struct xdg_toplevel* xdg_toplevel
7487  ) noexcept
7488 {
7489  if(decoration_manager == nullptr)
7490  {
7491  return nullptr;
7492  }
7493 
7494  /* *** From the xdg-decoration-unstable-v1 documentation ***
7495  *
7496  * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
7497  * buffer attached or committed is a client error.
7498  */
7499 
7500  zxdg_toplevel_decoration_v1* xdg_decoration =
7501  zxdg_decoration_manager_v1_get_toplevel_decoration(decoration_manager
7502  , xdg_toplevel
7503  );
7504 
7505  Yetani::XdgDecoration& decoration = xdg_decoration_map[xdg_surface];
7506  decoration.state_change = &(xdg_state_change_map[xdg_surface]);
7507  decoration.lambda = LambdaWindowDecorations_DoNothing;
7508  decoration.state = 0;
7509  decoration.is_present = false;
7510 
7511  zxdg_toplevel_decoration_v1_add_listener(xdg_decoration
7512  , &xdg_toplevel_decoration_listener
7513  , &decoration
7514  );
7515 
7516  return xdg_decoration;
7517 }
7518 
7519 
7525 void Yetani::xdgDecorationDestroy(struct xdg_surface* xdg_surface
7526  , struct xdg_toplevel* //xdg_toplevel ///< The XDG Toplevel
7527  , struct zxdg_toplevel_decoration_v1*& xdg_decoration
7528  ) noexcept
7529 {
7530  zxdg_toplevel_decoration_v1_destroy(xdg_decoration);
7531 
7532  if(xdg_decoration_map.contains(xdg_surface))
7533  {
7534  Yetani::XdgDecoration& decoration = xdg_decoration_map[xdg_surface];
7535  decoration.state_change = nullptr;
7536  decoration.lambda = nullptr;
7537  decoration.state = 0;
7538  decoration.is_present = false;
7539 
7540  xdg_decoration_map.erase(xdg_surface);
7541  }
7542 
7543  xdg_decoration = nullptr;
7544 }
7545 
7546 
7552 void Yetani::xdgDecorationChange(Yetani::XdgDecoration& decoration
7553  , const uint32_t decoration_state
7554  ) noexcept
7555 {
7556  if(decoration_state == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)
7557  {
7558  if(decoration.state != decoration_state)
7559  {
7560  decoration.state = decoration_state;
7561  decoration.is_present = false;
7562 
7563  decoration.lambda(
7565  );
7566  }
7567  }
7568  else if(decoration_state == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
7569  {
7570  if(decoration.state != decoration_state)
7571  {
7572  decoration.state = decoration_state;
7573  decoration.is_present = true;
7574  }
7575  else
7576  {
7577  decoration.is_present = !decoration.is_present;
7578  }
7579 
7580  if(decoration.is_present == true)
7581  {
7582  decoration.lambda(
7583  Yetani::WindowDecorations::Server_Side
7584  );
7585  }
7586  else
7587  {
7588  decoration.lambda(
7590  );
7591  }
7592  }
7593 }
7594 
7595 // }}}
7596 // {{{ XDG : Listener Handlers : Surface
7597 
7611 void Yetani::handlerXdgSurfaceConfigure(void* data
7612  , xdg_surface* xdg_surface
7613  , uint32_t serial
7614  ) noexcept
7615 {
7616  Yetani::XdgSurface& surface = *((Yetani::XdgSurface*)data);
7617  Yetani* yetani = surface.yetani;
7618 
7619  xdg_surface_ack_configure(xdg_surface, serial);
7620 
7621  VectorXdgStateChange& state_change = yetani->xdg_state_change_map[xdg_surface];
7622 
7623  if(state_change.empty())
7624  {
7625  return;
7626  }
7627 
7628  auto iter = std::begin(state_change);
7629  auto iter_end = std::end(state_change);
7630 
7631  while(iter != iter_end)
7632  {
7633  switch(*iter)
7634  {
7635  case Yetani::XdgState::Toplevel_Active:
7636  {
7637  Yetani::XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
7638 
7639  iter++;
7640  bool is_active = bool(*iter);
7641  if(toplevel.is_active != is_active)
7642  {
7643  toplevel.is_active = is_active;
7644 
7645  toplevel.is_active_lambda(is_active);
7646  }
7647  } break;
7648 
7649  case Yetani::XdgState::Toplevel_Attach_Buffer:
7650  {
7651  struct wl_surface* wl_surface = surface.wl_surface;
7652 
7653  SurfaceFrame& surface_frame =
7654  yetani->surface_frame_map[wl_surface];
7655 
7656  wl_surface_attach(surface_frame.wl_surface
7657  , surface_frame.buffer_next
7658  , 0, 0
7659  );
7660 
7661  surface_frame.callback = wl_surface_frame(surface_frame.wl_surface);
7662 
7663  wl_callback_add_listener(surface_frame.callback
7664  , &frame_callback_listener
7665  , &surface_frame
7666  );
7667 
7668  wl_surface_commit(surface_frame.wl_surface);
7669  } break;
7670 
7671  case Yetani::XdgState::Toplevel_Window_Normal:
7672  case Yetani::XdgState::Toplevel_Window_Maximized:
7673  case Yetani::XdgState::Toplevel_Window_Fullscreen:
7674  {
7675  struct wl_surface* wl_surface = surface.wl_surface;
7676 
7677  Yetani::XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
7678 
7679  Yetani::XdgState window_state = XdgState(*iter);
7680 
7681  Yetani::SizePixel size_pixel;
7682 
7683  iter++;
7684  size_pixel.width = *iter;
7685 
7686  iter++;
7687  size_pixel.height = *iter;
7688 
7689  if(toplevel.window_state != window_state)
7690  {
7691  xdgToplevelWindowChange(yetani
7692  , wl_surface
7693  , toplevel
7694  , window_state
7695  , size_pixel
7696  );
7697  }
7698  } break;
7699 
7700  case Yetani::XdgState::Toplevel_Resizing:
7701  {
7702  struct wl_surface* wl_surface = surface.wl_surface;
7703 
7704  Yetani::SizePixel size_pixel;
7705 
7706  iter++;
7707  size_pixel.width = *iter;
7708 
7709  iter++;
7710  size_pixel.height = *iter;
7711 
7712  if(size_pixel.width > 0
7713  && size_pixel.height > 0
7714  )
7715  {
7716  xdgToplevelSizeChange(yetani
7717  , wl_surface
7718  , size_pixel
7719  );
7720  }
7721  } break;
7722 
7723  case Yetani::XdgState::Toplevel_Decoration:
7724  {
7725  iter++;
7726  uint32_t decoration_state = *iter;
7727 
7728  Yetani::XdgDecoration& decoration = yetani->xdg_decoration_map[xdg_surface];
7729 
7730  xdgDecorationChange(decoration, decoration_state);
7731  } break;
7732  }
7733 
7734  iter++;
7735  }
7736 
7737  state_change.clear();
7738 }
7739 
7740 // }}}
7741 // {{{ XDG : Listener Handlers : Toplevel
7742 
7746 void Yetani::handlerXdgToplevelClose(void* data
7747  , struct xdg_toplevel* //xdg_toplevel ///< The toplevel surface
7748  ) noexcept
7749 {
7750  Yetani::XdgToplevel* toplevel = (Yetani::XdgToplevel*)data;
7751 
7752  toplevel->close_request_lambda();
7753 }
7754 
7755 
7759 void Yetani::handlerXdgToplevelConfigure(void* data
7760  , struct xdg_toplevel* //xdg_toplevel ///< The toplevel surface
7761  , int32_t width
7762  , int32_t height
7763  , struct wl_array* state_array
7764  ) noexcept
7765 {
7766  Yetani::XdgToplevel* toplevel = (Yetani::XdgToplevel*)data;
7767 
7768  Yetani::XdgState window_state = Yetani::XdgState::Toplevel_Window_Normal;
7769  int32_t is_active = 0;
7770 
7771  ZAKERO_YETANI__ARRAY_FOR_EACH(xdg_toplevel_state*, state_iter, state_array)
7772  {
7773  xdg_toplevel_state state = *state_iter;
7774 
7775  switch(state)
7776  {
7777  case XDG_TOPLEVEL_STATE_MAXIMIZED:
7778  window_state = Yetani::XdgState::Toplevel_Window_Maximized;
7779  break;
7780  case XDG_TOPLEVEL_STATE_FULLSCREEN:
7781  window_state = Yetani::XdgState::Toplevel_Window_Fullscreen;
7782  break;
7783  case XDG_TOPLEVEL_STATE_RESIZING:
7784  toplevel->state_change->push_back(Yetani::XdgState::Toplevel_Resizing);
7785  toplevel->state_change->push_back(width);
7786  toplevel->state_change->push_back(height);
7787  break;
7788  case XDG_TOPLEVEL_STATE_ACTIVATED:
7789  is_active = 1;
7790  break;
7791  case XDG_TOPLEVEL_STATE_TILED_LEFT:
7792  break;
7793  case XDG_TOPLEVEL_STATE_TILED_RIGHT:
7794  break;
7795  case XDG_TOPLEVEL_STATE_TILED_TOP:
7796  break;
7797  case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
7798  break;
7799  default:
7800  break;
7801  }
7802  }
7803 
7804  toplevel->state_change->push_back(window_state);
7805  toplevel->state_change->push_back(width);
7806  toplevel->state_change->push_back(height);
7807 
7808  toplevel->state_change->push_back(Yetani::XdgState::Toplevel_Active);
7809  toplevel->state_change->push_back(is_active);
7810 }
7811 
7812 // }}}
7813 // {{{ XDG : Listener Handlers : WM Base
7814 
7818 void Yetani::handlerXdgWmBasePing(void* //data ///< User data
7819  , struct xdg_wm_base* xdg_wm_base
7820  , uint32_t serial
7821  ) noexcept
7822 {
7823  xdg_wm_base_pong(xdg_wm_base, serial);
7824 }
7825 
7826 // }}}
7827 // {{{ XDG : Listener Handlers (Unstable) : Decoration
7828 
7832 void Yetani::handlerXdgToplevelDecorationConfigure(void* data
7833  , struct zxdg_toplevel_decoration_v1* //decoration ///< The Decoration object
7834  , uint32_t mode
7835  ) noexcept
7836 {
7837  Yetani::XdgDecoration* deco = (Yetani::XdgDecoration*)data;
7838 
7839  deco->state_change->push_back(Yetani::XdgState::Toplevel_Decoration);
7840  deco->state_change->push_back(mode);
7841 }
7842 
7843 // }}}
7844 // {{{ Window
7845 
8007  , std::error_code& error
8008  ) noexcept
8009 {
8010  return windowCreate(Yetani::SizeUnit::Millimeter
8011  , size
8012  , { 0, 0 }
8013  , { 0, 0 }
8014  , SHM_FORMAT_DEFAULT
8015  , error
8016  );
8017 }
8018 
8019 
8033  , const wl_shm_format format
8034  ) noexcept
8035 {
8036  std::error_code error;
8037 
8038  return windowCreate(Yetani::SizeUnit::Millimeter
8039  , size
8040  , { 0, 0 }
8041  , { 0, 0 }
8042  , format
8043  , error
8044  );
8045 }
8046 
8047 
8064  , const wl_shm_format format
8065  , std::error_code& error
8066  ) noexcept
8067 {
8068  return windowCreate(Yetani::SizeUnit::Millimeter
8069  , size
8070  , { 0, 0 }
8071  , { 0, 0 }
8072  , format
8073  , error
8074  );
8075 }
8076 
8077 
8092  , std::error_code& error
8093  ) noexcept
8094 {
8095  return windowCreate(Yetani::SizeUnit::Percent
8096  , { 0, 0 }
8097  , size
8098  , { 0, 0 }
8099  , SHM_FORMAT_DEFAULT
8100  , error
8101  );
8102 }
8103 
8104 
8118  , const wl_shm_format format
8119  ) noexcept
8120 {
8121  std::error_code error;
8122 
8123  return windowCreate(Yetani::SizeUnit::Percent
8124  , { 0, 0 }
8125  , size
8126  , { 0, 0 }
8127  , format
8128  , error
8129  );
8130 }
8131 
8132 
8149  , const wl_shm_format format
8150  , std::error_code& error
8151  ) noexcept
8152 {
8153  return windowCreate(Yetani::SizeUnit::Percent
8154  , { 0, 0 }
8155  , size
8156  , { 0, 0 }
8157  , format
8158  , error
8159  );
8160 }
8161 
8162 
8177  , std::error_code& error
8178  ) noexcept
8179 {
8180  return windowCreate(Yetani::SizeUnit::Pixel
8181  , { 0, 0 }
8182  , { 0, 0 }
8183  , size
8184  , SHM_FORMAT_DEFAULT
8185  , error
8186  );
8187 }
8188 
8189 
8203  , const wl_shm_format format
8204  ) noexcept
8205 {
8206  std::error_code error;
8207 
8208  return windowCreate(Yetani::SizeUnit::Pixel
8209  , { 0, 0 }
8210  , { 0, 0 }
8211  , size
8212  , format
8213  , error
8214  );
8215 }
8216 
8217 
8234  , const wl_shm_format format
8235  , std::error_code& error
8236  ) noexcept
8237 {
8238  return windowCreate(Yetani::SizeUnit::Pixel
8239  , { 0, 0 }
8240  , { 0, 0 }
8241  , size
8242  , format
8243  , error
8244  );
8245 }
8246 
8247 
8255 Yetani::Window* Yetani::windowCreate(const Yetani::SizeUnit size_unit
8256  , const Yetani::SizeMm& size_mm
8257  , const Yetani::SizePercent& size_percent
8258  , const Yetani::SizePixel& size_pixel
8259  , const wl_shm_format pixel_format
8260  , std::error_code& error
8261  ) noexcept
8262 {
8263  if((size_unit == Yetani::SizeUnit::Millimeter)
8264  && (size_mm.width <= 0 || size_mm.height <= 0)
8265  )
8266  {
8267  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8268 
8269  return nullptr;
8270  }
8271 
8272  if((size_unit == Yetani::SizeUnit::Percent)
8273  && (size_percent.width <= 0 || size_percent.height <= 0)
8274  )
8275  {
8276  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8277 
8278  return nullptr;
8279  }
8280 
8281  if((size_unit == Yetani::SizeUnit::Pixel)
8282  && (size_pixel.width <= 0 || size_pixel.height <= 0)
8283  )
8284  {
8285  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8286 
8287  return nullptr;
8288  }
8289 
8290  const std::string file_name = "Zakero.Yetani."
8291  + std::to_string(ZAKERO_STEADY_TIME_NOW(nanoseconds))
8292  ;
8293 
8294  struct WindowData window_data =
8295  { .yetani = this
8296  , .wl_shm = shm
8297  , .wl_output = nullptr
8298  , .file_name = file_name
8299  , .size_mm = size_mm
8300  , .size_percent = size_percent
8301  , .size_pixel = size_pixel
8302  , .size_unit = size_unit
8303  , .pixel_format = pixel_format
8304  , .error = ZAKERO_YETANI__ERROR(Error_None)
8305  };
8306 
8307  windowDataInit(window_data);
8308 
8309  if(window_data.error)
8310  {
8311  error = window_data.error;
8312 
8313  return nullptr;
8314  }
8315 
8316  Yetani::Window* window = new Window(&window_data);
8317 
8318  if(window_data.error)
8319  {
8320  delete window;
8321  window = nullptr;
8322 
8323  ZAKERO_YETANI__DEBUG << to_string(window_data.error) << "\n";
8324 
8325  error = ZAKERO_YETANI__ERROR(Error_Window_Initialization_Failed);
8326 
8327  return nullptr;
8328  }
8329 
8330  error = ZAKERO_YETANI__ERROR(Error_None);
8331 
8332  return window;
8333 }
8334 
8335 
8339 void Yetani::windowDataInit(Yetani::WindowData& window_data
8340  ) noexcept
8341 {
8342  windowDataInitOutput(window_data);
8343 
8344  if(window_data.error)
8345  {
8346  return;
8347  }
8348 
8349  window_data.size_pixel.width = std::max(1, window_data.size_pixel.width);
8350  window_data.size_pixel.height = std::max(1, window_data.size_pixel.height);
8351 
8352  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8353 }
8354 
8355 
8359 void Yetani::windowDataInitOutput(Yetani::WindowData& window_data
8360  ) noexcept
8361 {
8362  std::lock_guard<std::mutex> lock(output_data.mutex);
8363 
8364  if(output_data.output_map.empty())
8365  {
8366  window_data.error = ZAKERO_YETANI__ERROR(Error_No_Output_Available);
8367 
8368  return;
8369  }
8370 
8371  const auto& iter = output_data.output_map.begin();
8372 
8373  window_data.wl_output = iter->first;
8374  Yetani::Output& output = iter->second;
8375 
8376  if(window_data.size_unit == Yetani::SizeUnit::Millimeter)
8377  {
8378  auto px = convertMmToPixel(output
8379  , window_data.size_mm.width
8380  , window_data.size_mm.height
8381  );
8382 
8383  auto pc = convertPixelToPercent(output
8384  , px.first
8385  , px.second
8386  );
8387 
8388  window_data.size_mm = window_data.size_mm;
8389  window_data.size_percent = { pc.first, pc.second };
8390  window_data.size_pixel = { px.first, px.second };
8391  }
8392  else if(window_data.size_unit == Yetani::SizeUnit::Percent)
8393  {
8394  auto px = convertPercentToPixel(output
8395  , window_data.size_percent.width
8396  , window_data.size_percent.height
8397  );
8398 
8399  auto mm = convertPixelToMm(output
8400  , px.first
8401  , px.second
8402  );
8403 
8404  window_data.size_mm = { mm.first, mm.second };
8405  window_data.size_percent = window_data.size_percent;
8406  window_data.size_pixel = { px.first, px.second };
8407  }
8408  else if(window_data.size_unit == Yetani::SizeUnit::Pixel)
8409  {
8410  auto mm = convertPixelToMm(output
8411  , window_data.size_pixel.width
8412  , window_data.size_pixel.height
8413  );
8414 
8415  auto pc = convertPixelToPercent(output
8416  , window_data.size_pixel.width
8417  , window_data.size_pixel.height
8418  );
8419 
8420  window_data.size_mm = { mm.first, mm.second };
8421  window_data.size_percent = { pc.first, pc.second };
8422  window_data.size_pixel = window_data.size_pixel;
8423  }
8424 
8425  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8426 }
8427 
8428 
8432 void Yetani::windowInitMemory(Yetani::WindowData& window_data
8433  , Yetani::Window::Memory& window_memory
8434  ) noexcept
8435 {
8436  size_t size_in_bytes = sizeInBytes(window_data.size_pixel
8437  , window_data.pixel_format
8438  ) * 3;
8439 
8440  window_data.error = window_memory.memory_pool.init(size_in_bytes
8441  , true
8442  , zakero::MemoryPool::Alignment::Bits_32
8443  );
8444 
8445  if(window_data.error)
8446  {
8447  return;
8448  }
8449 
8450  window_memory.wl_shm_pool = wl_shm_create_pool(window_data.wl_shm
8451  , window_memory.memory_pool.fd()
8452  , window_memory.memory_pool.size()
8453  );
8454 
8455  window_memory.memory_pool.sizeOnChange([&](size_t new_size)
8456  {
8457  wl_shm_pool_resize(window_memory.wl_shm_pool, new_size);
8458  });
8459 
8460  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8461 }
8462 
8463 
8467 void Yetani::windowInitOutput(Yetani::WindowData& window_data
8468  , struct wl_surface* wl_surface
8469  ) noexcept
8470 {
8471  std::lock_guard<std::mutex> lock(output_data.mutex);
8472 
8473  output_data.surface_output_map[wl_surface].push_back(window_data.wl_output);
8474 }
8475 
8476 
8480 void Yetani::windowEraseMemory(Yetani::Window::Memory& window_memory
8481  ) noexcept
8482 {
8483  if(window_memory.wl_shm_pool)
8484  {
8485  wl_shm_pool_destroy(window_memory.wl_shm_pool);
8486  window_memory.wl_shm_pool = nullptr;
8487  }
8488 }
8489 
8490 
8494 void Yetani::windowEraseOutput(struct wl_surface* wl_surface
8495  ) noexcept
8496 {
8497  std::lock_guard<std::mutex> lock(output_data.mutex);
8498 
8499  if(output_data.surface_output_map.contains(wl_surface))
8500  {
8501  output_data.surface_output_map.erase(wl_surface);
8502  }
8503 }
8504 
8505 
8509 void Yetani::windowEraseSurfaceExtent(struct wl_surface* wl_surface
8510  ) noexcept
8511 {
8512  std::lock_guard<std::mutex> lock(surface_extent_mutex);
8513 
8514  if(surface_extent_map.contains(wl_surface))
8515  {
8516  surface_extent_map.erase(wl_surface);
8517  }
8518 }
8519 
8520 
8524 void Yetani::windowAdd(Yetani::Window* window
8525  ) noexcept
8526 {
8527  std::lock_guard<std::mutex> lock(window_vector_mutex);
8528 
8529  window_vector.push_back(window);
8530 }
8531 
8532 
8536 void Yetani::windowRemove(Yetani::Window* window
8537  ) noexcept
8538 {
8539  std::lock_guard<std::mutex> lock(window_vector_mutex);
8540 
8541  zakero::vectorErase(window_vector, window);
8542 }
8543 
8544 // }}}
8545 // {{{ Window : Documentation
8546 
8712 // }}}
8713 // {{{ Window : Constructor / Destructor
8714 
8743  )
8744  : yetani {((Yetani::WindowData*)ptr)->yetani}
8745  , wl_buffer {nullptr}
8746  , wl_surface {nullptr}
8747  , xdg_surface {nullptr}
8748  , xdg_toplevel {nullptr}
8749  , xdg_decoration {nullptr}
8750  , window_memory {nullptr, ((Yetani::WindowData*)ptr)->file_name}
8751  , pixel_format {((Yetani::WindowData*)ptr)->pixel_format}
8752 {
8753  Yetani::WindowData& window_data = *((Yetani::WindowData*)ptr);
8754 
8755  yetani->windowInitMemory(window_data, window_memory);
8756  if(window_data.error)
8757  {
8758  return;
8759  }
8760 
8761  wl_surface = yetani->surfaceCreate(yetani
8762  , pixel_format
8763  , window_data.size_pixel
8764  , false
8765  , window_memory
8766  );
8767 
8768  xdg_surface = yetani->xdgSurfaceCreate(wl_surface);
8769 
8770  yetani->xdgSurfaceSetExtent(wl_surface
8771  , window_data.size_unit
8772  , window_data.size_mm
8773  , window_data.size_percent
8774  , window_data.size_pixel
8775  );
8776 
8777  xdg_toplevel = yetani->xdgToplevelCreate(xdg_surface);
8778 
8779  xdg_decoration = yetani->xdgDecorationCreate(xdg_surface, xdg_toplevel);
8780 
8781  wl_surface_commit(wl_surface);
8782 
8783  yetani->windowInitOutput(window_data, wl_surface);
8784  if(window_data.error)
8785  {
8786  return;
8787  }
8788 
8789  yetani->windowAdd(this);
8790 }
8791 
8792 
8797 {
8798  yetani->windowRemove(this);
8799 
8800  if(xdg_decoration != nullptr)
8801  {
8802  yetani->xdgDecorationDestroy(xdg_surface, xdg_toplevel, xdg_decoration);
8803  }
8804 
8805  if(xdg_toplevel != nullptr)
8806  {
8807  yetani->xdgToplevelDestroy(xdg_surface, xdg_toplevel);
8808  }
8809 
8810  if(xdg_surface != nullptr)
8811  {
8812  yetani->xdgSurfaceDestroy(wl_surface, xdg_surface);
8813  }
8814 
8815  if(wl_surface != nullptr)
8816  {
8817  yetani->windowEraseOutput(wl_surface);
8818  yetani->surfaceDestroy(yetani, wl_surface);
8819  yetani->windowEraseSurfaceExtent(wl_surface);
8820  }
8821 
8822  yetani->windowEraseMemory(window_memory);
8823 }
8824 
8825 // }}}
8826 // {{{ Window : Cursor
8827 
8841 std::error_code Yetani::Window::cursorUse(const std::string& name
8842  ) noexcept
8843 {
8844  if(name.empty())
8845  {
8846  return yetani->cursorDetach(wl_surface);
8847  }
8848 
8849  return yetani->cursorAttach(name, wl_surface);
8850 }
8851 
8852 
8859 {
8860  yetani->cursorHide(wl_surface);
8861 }
8862 
8863 
8870 {
8871  yetani->cursorShow(wl_surface);
8872 }
8873 
8874 // }}}
8875 // {{{ Window : Settings
8876 
8893 void Yetani::Window::setClass(const std::string& class_name
8894  ) noexcept
8895 {
8896  xdg_toplevel_set_app_id(xdg_toplevel, class_name.c_str());
8897 }
8898 
8899 
8906 void Yetani::Window::setTitle(const std::string& title
8907  ) noexcept
8908 {
8909  xdg_toplevel_set_title(xdg_toplevel, title.c_str());
8910 }
8911 
8912 
8933  ) noexcept
8934 {
8935  if(yetani->decoration_manager == nullptr)
8936  {
8937  return ZAKERO_YETANI__ERROR(Error_Server_Side_Decorations_Not_Available);
8938  }
8939 
8940  uint32_t decoration_state = decorations == Yetani::WindowDecorations::Server_Side
8941  ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
8942  : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE
8943  ;
8944 
8945  zxdg_toplevel_decoration_v1_set_mode(xdg_decoration
8946  , decoration_state
8947  );
8948 
8949  return ZAKERO_YETANI__ERROR(Error_None);
8950 }
8951 
8952 
8961 {
8962  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
8963 
8964  Yetani::WindowMode window_mode = Yetani::toWindowMode(toplevel.window_state);
8965 
8966  return window_mode;
8967 }
8968 
8969 
8979  ) noexcept
8980 {
8981  XdgState window_state = Yetani::toXdgState(window_mode);
8982 
8983  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
8984 
8985  if(toplevel.window_state == window_state)
8986  {
8987  return true;
8988  }
8989 
8990  return false;
8991 }
8992 
8993 
9003  ) noexcept
9004 {
9005  XdgState window_state = Yetani::toXdgState(window_mode);
9006 
9007  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9008 
9009  if(toplevel.window_state == window_state)
9010  {
9011  return;
9012  }
9013 
9014  switch(window_mode)
9015  {
9016  case WindowMode::Fullscreen:
9017  xdg_toplevel_set_fullscreen(xdg_toplevel, nullptr);
9018  break;
9019 
9020  case WindowMode::Maximized:
9021  xdg_toplevel_set_maximized(xdg_toplevel);
9022  break;
9023 
9024  case WindowMode::Normal:
9025  xdg_toplevel_unset_fullscreen(xdg_toplevel);
9026  xdg_toplevel_unset_maximized(xdg_toplevel);
9027  break;
9028  }
9029 }
9030 
9031 
9048 std::error_code Yetani::Window::setSize(const Yetani::SizeMm& size
9049  ) noexcept
9050 {
9051  if(size.width <= 0 || size.height <= 0)
9052  {
9053  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9054  }
9055 
9056  Yetani::SizePixel size_pixel = convertToPixel(size);
9057 
9058  if(size_pixel.width <= 0)
9059  {
9060  size_pixel.width = 1;
9061  }
9062 
9063  if(size_pixel.height <= 0)
9064  {
9065  size_pixel.height = 1;
9066  }
9067 
9068  yetani->surface_resize_mutex_map[wl_surface].lock();
9069  {
9070  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9071 
9072  surface_extent.preferred_unit = Yetani::SizeUnit::Millimeter;
9073  surface_extent.preferred_mm = size;
9074  surface_extent.size_pixel = size_pixel;
9075 
9076  surfaceCalculateSize(yetani, wl_surface, size_pixel);
9077  }
9078  yetani->surface_resize_mutex_map[wl_surface].unlock();
9079 
9080  return ZAKERO_YETANI__ERROR(Error_None);
9081 }
9082 
9083 
9100 std::error_code Yetani::Window::setSize(const Yetani::SizePercent& size
9101  ) noexcept
9102 {
9103  if(size.width <= 0 || size.height <= 0)
9104  {
9105  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9106  }
9107 
9108  Yetani::SizePixel size_pixel = convertToPixel(size);
9109 
9110  if(size_pixel.width <= 0)
9111  {
9112  size_pixel.width = 1;
9113  }
9114 
9115  if(size_pixel.height <= 0)
9116  {
9117  size_pixel.height = 1;
9118  }
9119 
9120  yetani->surface_resize_mutex_map[wl_surface].lock();
9121  {
9122  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9123 
9124  surface_extent.preferred_unit = Yetani::SizeUnit::Percent;
9125  surface_extent.preferred_percent = size;
9126  surface_extent.size_pixel = size_pixel;
9127 
9128  surfaceCalculateSize(yetani, wl_surface, size_pixel);
9129  }
9130  yetani->surface_resize_mutex_map[wl_surface].unlock();
9131 
9132  return ZAKERO_YETANI__ERROR(Error_None);
9133 }
9134 
9135 
9152 std::error_code Yetani::Window::setSize(const Yetani::SizePixel& size
9153  ) noexcept
9154 {
9155  if(size.width <= 0 || size.height <= 0)
9156  {
9157  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9158  }
9159 
9160  yetani->surface_resize_mutex_map[wl_surface].lock();
9161  {
9162  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9163 
9164  surface_extent.preferred_unit = Yetani::SizeUnit::Pixel;
9165  surface_extent.size_pixel = size;
9166 
9167  surfaceCalculateSize(yetani, wl_surface, size);
9168  }
9169  yetani->surface_resize_mutex_map[wl_surface].unlock();
9170 
9171  return ZAKERO_YETANI__ERROR(Error_None);
9172 }
9173 
9174 
9186 std::error_code Yetani::Window::setSizeMinMax(const Yetani::SizeMm& size_min
9187  , const Yetani::SizeMm& size_max
9188  ) noexcept
9189 {
9190  std::error_code error = validateMinMax<Yetani::SizeMm>(size_min, size_max);
9191  if(error)
9192  {
9193  return error;
9194  }
9195 
9196  Yetani::SizePixel size_pixel_min;
9197  Yetani::SizePixel size_pixel_max;
9198 
9199  {
9200  Yetani::OutputData& output_data = yetani->output_data;
9201 
9202  std::lock_guard<std::mutex> lock(output_data.mutex);
9203 
9204  Yetani::VectorWlOutput& vector = output_data.surface_output_map[wl_surface];
9205  struct wl_output* wl_output = vector.front();
9206  const Yetani::Output& output = output_data.output_map[wl_output];
9207 
9208  auto min = yetani->convertMmToPixel(output, size_min.width, size_min.height);
9209  size_pixel_min = { min.first, min.second };
9210 
9211  auto max = yetani->convertMmToPixel(output, size_max.width, size_max.height);
9212  size_pixel_max = { max.first, max.second };
9213  }
9214 
9215  yetani->xdgToplevelSizeMinMaxChange(yetani
9216  , xdg_toplevel
9217  , wl_surface
9218  , size_pixel_min
9219  , size_pixel_max
9220  );
9221 
9222  return ZAKERO_YETANI__ERROR(Error_None);
9223 }
9224 
9225 
9237 std::error_code Yetani::Window::setSizeMinMax(const Yetani::SizePercent& size_min
9238  , const Yetani::SizePercent& size_max
9239  ) noexcept
9240 {
9241  std::error_code error = validateMinMax<Yetani::SizePercent>(size_min, size_max);
9242  if(error)
9243  {
9244  return error;
9245  }
9246 
9247  Yetani::SizePixel size_pixel_min;
9248  Yetani::SizePixel size_pixel_max;
9249 
9250  {
9251  Yetani::OutputData& output_data = yetani->output_data;
9252 
9253  std::lock_guard<std::mutex> lock(output_data.mutex);
9254 
9255  Yetani::VectorWlOutput& vector = output_data.surface_output_map[wl_surface];
9256  struct wl_output* wl_output = vector.front();
9257  const Yetani::Output& output = output_data.output_map[wl_output];
9258 
9259  auto min = yetani->convertPercentToPixel(output, size_min.width, size_min.height);
9260  size_pixel_min = { min.first, min.second };
9261 
9262  auto max = yetani->convertPercentToPixel(output, size_max.width, size_max.height);
9263  size_pixel_max = { max.first, max.second };
9264  }
9265 
9266  yetani->xdgToplevelSizeMinMaxChange(yetani
9267  , xdg_toplevel
9268  , wl_surface
9269  , size_pixel_min
9270  , size_pixel_max
9271  );
9272 
9273  return ZAKERO_YETANI__ERROR(Error_None);
9274 }
9275 
9276 
9288 std::error_code Yetani::Window::setSizeMinMax(const Yetani::SizePixel& size_min
9289  , const Yetani::SizePixel& size_max
9290  ) noexcept
9291 {
9292  std::error_code error = validateMinMax<Yetani::SizePixel>(size_min, size_max);
9293  if(error)
9294  {
9295  return error;
9296  }
9297 
9298  yetani->xdgToplevelSizeMinMaxChange(yetani
9299  , xdg_toplevel
9300  , wl_surface
9301  , size_min
9302  , size_max
9303  );
9304 
9305  return ZAKERO_YETANI__ERROR(Error_None);
9306 }
9307 
9308 // }}}
9309 // {{{ Window : Rendering
9310 
9347 std::error_code Yetani::Window::imageNext(uint8_t*& image
9348  , Yetani::SizePixel& size
9349  ) noexcept
9350 {
9351  if(wl_buffer != nullptr)
9352  {
9353  bufferDestroy(wl_buffer);
9354  }
9355 
9356  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
9357 
9358  yetani->surface_resize_mutex_map[wl_surface].lock();
9359  {
9360  wl_buffer = bufferCreateAndRelease(yetani
9361  , surface_size
9362  , &window_memory
9363  );
9364  }
9365  yetani->surface_resize_mutex_map[wl_surface].unlock();
9366 
9367  image = window_memory.memory_pool.addressOf(
9368  yetani->buffer.map[wl_buffer].offset
9369  );
9370 
9371  size = { surface_size.width, surface_size.height };
9372 
9373  return ZAKERO_YETANI__ERROR(Error_None);
9374 }
9375 
9376 
9384 {
9385  if(wl_buffer == nullptr)
9386  {
9387  // This nullptr check is needed because:
9388  // - If imagePresent() is called before imageNext() then
9389  // wl_buffer could be nullptr.
9390  // - There is a chance that a valid "buffer_next" can be
9391  // replaced with a nullptr, and this will cause a
9392  // frame-drop.
9393 
9394  return;
9395  }
9396 
9397  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
9398 
9399  wl_buffer = surface_frame.buffer_next.exchange(wl_buffer);
9400 }
9401 
9402 
9415 uint32_t Yetani::Window::time() const noexcept
9416 {
9417  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
9418 
9419  return surface_frame.time_ms;
9420 }
9421 
9422 // }}}
9423 // {{{ Window : Misc
9424 
9433 uint8_t Yetani::Window::bytesPerPixel() const noexcept
9434 {
9435  return yetani->shmFormatBytesPerPixel(pixel_format);
9436 }
9437 
9438 
9447 {
9448  xdg_toplevel_set_minimized(xdg_toplevel);
9449 }
9450 
9451 // }}}
9452 // {{{ Window : Measurement Conversion
9453 
9462  ) const noexcept
9463 {
9464  const Yetani::OutputData& output_data = yetani->output_data;
9465 
9466  std::lock_guard<std::mutex> lock(output_data.mutex);
9467 
9468  struct wl_output* wl_output = output_data.surface_output_map.at(wl_surface).front();
9469  const Yetani::Output& output = output_data.output_map.at(wl_output);
9470 
9471  auto p = yetani->convertPixelToMm(output, point.x, point.y);
9472 
9473  return { point.time, p.first, p.second };
9474 }
9475 
9476 
9485  ) const noexcept
9486 {
9487  const Yetani::OutputData& output_data = yetani->output_data;
9488 
9489  std::lock_guard<std::mutex> lock(output_data.mutex);
9490 
9491  struct wl_output* wl_output = output_data.surface_output_map.at(wl_surface).front();
9492  const Yetani::Output& output = output_data.output_map.at(wl_output);
9493 
9494  auto p = yetani->convertPixelToPercent(output, point.x, point.y);
9495 
9496  return { point.time, p.first, p.second };
9497 }
9498 
9499 
9508  ) const noexcept
9509 {
9510  Yetani::OutputData& output_data = yetani->output_data;
9511 
9512  std::lock_guard<std::mutex> lock(output_data.mutex);
9513 
9514  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9515  const Yetani::Output& output = output_data.output_map[wl_output];
9516 
9517  auto p = yetani->convertMmToPixel(output, point.x, point.y);
9518 
9519  return { point.time, p.first, p.second };
9520 }
9521 
9522 
9531  ) const noexcept
9532 {
9533  Yetani::OutputData& output_data = yetani->output_data;
9534 
9535  std::lock_guard<std::mutex> lock(output_data.mutex);
9536 
9537  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9538  const Yetani::Output& output = output_data.output_map[wl_output];
9539 
9540  auto p = yetani->convertPercentToPixel(output, point.x, point.y);
9541 
9542  return { point.time, p.first, p.second };
9543 }
9544 
9545 
9554  ) const noexcept
9555 {
9556  Yetani::OutputData& output_data = yetani->output_data;
9557 
9558  std::lock_guard<std::mutex> lock(output_data.mutex);
9559 
9560  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9561  const Yetani::Output& output = output_data.output_map[wl_output];
9562 
9563  auto p = yetani->convertPixelToMm(output, size.width, size.height);
9564 
9565  return { p.first, p.second };
9566 }
9567 
9568 
9577  ) const noexcept
9578 {
9579  Yetani::OutputData& output_data = yetani->output_data;
9580 
9581  std::lock_guard<std::mutex> lock(output_data.mutex);
9582 
9583  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9584  const Yetani::Output& output = output_data.output_map[wl_output];
9585 
9586  auto p = yetani->convertPixelToPercent(output, size.width, size.height);
9587 
9588  return { p.first, p.second };
9589 }
9590 
9591 
9600  ) const noexcept
9601 {
9602  Yetani::OutputData& output_data = yetani->output_data;
9603 
9604  std::lock_guard<std::mutex> lock(output_data.mutex);
9605 
9606  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9607  const Yetani::Output& output = output_data.output_map[wl_output];
9608 
9609  auto p = yetani->convertMmToPixel(output, size.width, size.height);
9610 
9611  return { p.first, p.second };
9612 }
9613 
9614 
9623  ) const noexcept
9624 {
9625  Yetani::OutputData& output_data = yetani->output_data;
9626 
9627  std::lock_guard<std::mutex> lock(output_data.mutex);
9628 
9629  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9630  const Yetani::Output& output = output_data.output_map[wl_output];
9631 
9632  auto p = yetani->convertPercentToPixel(output, size.width, size.height);
9633 
9634  return { p.first, p.second };
9635 }
9636 
9637 // }}}
9638 // {{{ Window : Event Handling
9639 
9652  ) noexcept
9653 {
9654  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9655 
9656  if(lambda == nullptr)
9657  {
9658  toplevel.close_request_lambda = Lambda_DoNothing;
9659  }
9660  else
9661  {
9662  toplevel.close_request_lambda = lambda;
9663  }
9664 }
9665 
9666 
9677  ) noexcept
9678 {
9679  XdgDecoration& decoration = yetani->xdg_decoration_map[xdg_surface];
9680 
9681  if(lambda == nullptr)
9682  {
9683  decoration.lambda = LambdaWindowDecorations_DoNothing;
9684  }
9685  else
9686  {
9687  decoration.lambda = lambda;
9688  }
9689 }
9690 
9691 
9706  ) noexcept
9707 {
9708  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9709 
9710  if(lambda == nullptr)
9711  {
9712  toplevel.is_active_lambda = LambdaBool_DoNothing;
9713  }
9714  else
9715  {
9716  toplevel.is_active_lambda = lambda;
9717  }
9718 }
9719 
9720 
9727  ) noexcept
9728 {
9729  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9730  {
9731  return;
9732  }
9733 
9734  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9735 
9736  if(lambda == nullptr)
9737  {
9738  event.on_enter = Lambda_DoNothing;
9739  }
9740  else
9741  {
9742  event.on_enter = lambda;
9743  }
9744 }
9745 
9746 
9753  ) noexcept
9754 {
9755  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9756  {
9757  return;
9758  }
9759 
9760  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9761 
9762  if(lambda == nullptr)
9763  {
9764  event.on_leave = Lambda_DoNothing;
9765  }
9766  else
9767  {
9768  event.on_leave = lambda;
9769  }
9770 }
9771 
9772 
9781  ) noexcept
9782 {
9783  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9784  {
9785  return;
9786  }
9787 
9788  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9789 
9790  if(lambda == nullptr)
9791  {
9792  event.on_key = LambdaKey_DoNothing;
9793  }
9794  else
9795  {
9796  event.on_key = lambda;
9797  }
9798 }
9799 
9800 
9808  ) noexcept
9809 {
9810  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9811 
9812  if(lambda == nullptr)
9813  {
9814  toplevel.window_state_lambda = LambdaWindowMode_DoNothing;
9815  }
9816  else
9817  {
9818  toplevel.window_state_lambda = lambda;
9819  }
9820 }
9821 
9822 
9837  ) noexcept
9838 {
9839  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9840 
9841  if(lambda == nullptr)
9842  {
9843  event.on_size_mm_change = LambdaSizeMm_DoNothing;
9844  }
9845  else
9846  {
9847  event.on_size_mm_change = lambda;
9848  }
9849 }
9850 
9851 
9866  ) noexcept
9867 {
9868  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9869 
9870  if(lambda == nullptr)
9871  {
9872  event.on_size_percent_change = LambdaSizePercent_DoNothing;
9873  }
9874  else
9875  {
9876  event.on_size_percent_change = lambda;
9877  }
9878 }
9879 
9880 
9895  ) noexcept
9896 {
9897  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9898 
9899  if(lambda == nullptr)
9900  {
9901  event.on_size_pixel_change = LambdaSizePixel_DoNothing;
9902  }
9903  else
9904  {
9905  event.on_size_pixel_change = lambda;
9906  }
9907 }
9908 
9909 
9918  ) noexcept
9919 {
9920  if(yetani->pointer.event_map.contains(wl_surface) == false)
9921  {
9922  return;
9923  }
9924 
9925  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9926 
9927  if(lambda == nullptr)
9928  {
9929  event.on_button_mm = LambdaButtonMm_DoNothing;
9930  }
9931  else
9932  {
9933  event.on_button_mm = lambda;
9934  }
9935 }
9936 
9937 
9946  ) noexcept
9947 {
9948  if(yetani->pointer.event_map.contains(wl_surface) == false)
9949  {
9950  return;
9951  }
9952 
9953  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9954 
9955  if(lambda == nullptr)
9956  {
9957  event.on_button_percent = LambdaButtonPercent_DoNothing;
9958  }
9959  else
9960  {
9961  event.on_button_percent = lambda;
9962  }
9963 }
9964 
9965 
9974  ) noexcept
9975 {
9976  if(yetani->pointer.event_map.contains(wl_surface) == false)
9977  {
9978  return;
9979  }
9980 
9981  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9982 
9983  if(lambda == nullptr)
9984  {
9985  event.on_button_pixel = LambdaButtonPixel_DoNothing;
9986  }
9987  else
9988  {
9989  event.on_button_pixel = lambda;
9990  }
9991 }
9992 
9993 
10005  ) noexcept
10006 {
10007  if(yetani->pointer.event_map.contains(wl_surface) == false)
10008  {
10009  return;
10010  }
10011 
10012  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10013 
10014  if(lambda == nullptr)
10015  {
10016  event.on_enter_mm = LambdaPointMm_DoNothing;
10017  }
10018  else
10019  {
10020  event.on_enter_mm = lambda;
10021  }
10022 }
10023 
10024 
10036  ) noexcept
10037 {
10038  if(yetani->pointer.event_map.contains(wl_surface) == false)
10039  {
10040  return;
10041  }
10042 
10043  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10044 
10045  if(lambda == nullptr)
10046  {
10047  event.on_enter_percent = LambdaPointPercent_DoNothing;
10048  }
10049  else
10050  {
10051  event.on_enter_percent = lambda;
10052  }
10053 }
10054 
10055 
10067  ) noexcept
10068 {
10069  if(yetani->pointer.event_map.contains(wl_surface) == false)
10070  {
10071  return;
10072  }
10073 
10074  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10075 
10076  if(lambda == nullptr)
10077  {
10078  event.on_enter_pixel = LambdaPointPixel_DoNothing;
10079  }
10080  else
10081  {
10082  event.on_enter_pixel = lambda;
10083  }
10084 }
10085 
10086 
10095  ) noexcept
10096 {
10097  if(yetani->pointer.event_map.contains(wl_surface) == false)
10098  {
10099  return;
10100  }
10101 
10102  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10103 
10104  if(lambda == nullptr)
10105  {
10106  event.on_leave = Lambda_DoNothing;
10107  }
10108  else
10109  {
10110  event.on_leave = lambda;
10111  }
10112 }
10113 
10114 
10123  ) noexcept
10124 {
10125  if(yetani->pointer.event_map.contains(wl_surface) == false)
10126  {
10127  return;
10128  }
10129 
10130  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10131 
10132  if(lambda == nullptr)
10133  {
10134  event.on_motion_mm = LambdaPointMm_DoNothing;
10135  }
10136  else
10137  {
10138  event.on_motion_mm = lambda;
10139  }
10140 }
10141 
10142 
10151  ) noexcept
10152 {
10153  if(yetani->pointer.event_map.contains(wl_surface) == false)
10154  {
10155  return;
10156  }
10157 
10158  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10159 
10160  if(lambda == nullptr)
10161  {
10162  event.on_motion_percent = LambdaPointPercent_DoNothing;
10163  }
10164  else
10165  {
10166  event.on_motion_percent = lambda;
10167  }
10168 }
10169 
10170 
10179  ) noexcept
10180 {
10181  if(yetani->pointer.event_map.contains(wl_surface) == false)
10182  {
10183  return;
10184  }
10185 
10186  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10187 
10188  if(lambda == nullptr)
10189  {
10190  event.on_motion_pixel = LambdaPointPixel_DoNothing;
10191  }
10192  else
10193  {
10194  event.on_motion_pixel = lambda;
10195  }
10196 }
10197 
10198 
10206  ) noexcept
10207 {
10208  if(yetani->pointer.event_map.contains(wl_surface) == false)
10209  {
10210  return;
10211  }
10212 
10213  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10214 
10215  if(lambda == nullptr)
10216  {
10217  event.on_axis = LambdaAxis_DoNothing;
10218  }
10219  else
10220  {
10221  event.on_axis = lambda;
10222  }
10223 }
10224 
10225 
10233  ) noexcept
10234 {
10235  if(yetani->pointer.event_map.contains(wl_surface) == false)
10236  {
10237  return;
10238  }
10239 
10240  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10241 
10242  if(lambda == nullptr)
10243  {
10244  event.on_axis_source = Lambda_DoNothing;
10245  }
10246  else
10247  {
10248  event.on_axis_source = lambda;
10249  }
10250 }
10251 
10252 
10260  ) noexcept
10261 {
10262  if(yetani->pointer.event_map.contains(wl_surface) == false)
10263  {
10264  return;
10265  }
10266 
10267  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10268 
10269  if(lambda == nullptr)
10270  {
10271  event.on_axis_stop = Lambda_DoNothing;
10272  }
10273  else
10274  {
10275  event.on_axis_stop = lambda;
10276  }
10277 }
10278 
10279 
10287  ) noexcept
10288 {
10289  if(yetani->pointer.event_map.contains(wl_surface) == false)
10290  {
10291  return;
10292  }
10293 
10294  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10295 
10296  if(lambda == nullptr)
10297  {
10298  event.on_axis_discrete = Lambda_DoNothing;
10299  }
10300  else
10301  {
10302  event.on_axis_discrete = lambda;
10303  }
10304 }
10305 
10306 // }}}
10307 // {{{ Window : Helpers
10308 
10309 
10310 // }}}
10311 // {{{ Convenience
10312 
10320 std::string to_string(const wl_shm_format shm_format
10321  ) noexcept
10322 {
10323  return Yetani::shmFormatName(shm_format);
10324 }
10325 
10326 
10335 std::string to_string(const Yetani::KeyModifier& key_modifier
10336  ) noexcept
10337 {
10338  auto mod_to_str = [](std::string& s, uint32_t m)
10339  {
10340  s += "[";
10341  std::string delim = "";
10342 
10344  {
10345  s += delim + "\"Shift\"";
10346  delim = ",";
10347  }
10348 
10350  {
10351  s += delim + "\"CapsLock\"";
10352  delim = ",";
10353  }
10354 
10356  {
10357  s += delim + "\"Control\"";
10358  delim = ",";
10359  }
10360 
10361  if(m & Yetani::KeyModifier_Alt)
10362  {
10363  s += delim + "\"Alt\"";
10364  delim = ",";
10365  }
10366 
10367  if(m & Yetani::KeyModifier_Meta)
10368  {
10369  s += delim + "\"Meta\"";
10370  }
10371 
10372  s += "]";
10373  };
10374 
10375  std::string str = "{ \"pressed\": ";
10376  mod_to_str(str, key_modifier.pressed);
10377 
10378  str += ", \"latched\": ";
10379  mod_to_str(str, key_modifier.latched);
10380 
10381  str += ", \"locked\": ";
10382  mod_to_str(str, key_modifier.locked);
10383 
10384  str += " }";
10385 
10386  return str;
10387 }
10388 
10389 
10397 std::string to_string(const Yetani::KeyState key_state
10398  ) noexcept
10399 {
10400  switch(key_state)
10401  {
10402  case Yetani::KeyState::Pressed: return "Pressed";
10403  case Yetani::KeyState::Released: return "Released";
10404  case Yetani::KeyState::Repeat: return "Repeat";
10405  default: return "";
10406  }
10407 }
10408 
10409 
10417 std::string to_string(const Yetani::Output& output
10418  ) noexcept
10419 {
10420  return "{\tx: " + std::to_string(output.x)
10421  + "\n,\ty: " + std::to_string(output.y)
10422  + "\n,\tphysical_width_mm: " + std::to_string(output.physical_width_mm)
10423  + "\n,\tphysical_height_mm: " + std::to_string(output.physical_height_mm)
10424  + "\n,\tsubpixel: " + std::to_string(output.subpixel)
10425  + "\n,\tsubpixel_name: \"" + Yetani::outputSubpixelName(output.subpixel) + "\""
10426  + "\n,\tmake: \"" + output.make + "\""
10427  + "\n,\tmodel: \"" + output.model + "\""
10428  + "\n,\ttransform: " + std::to_string(output.transform)
10429  + "\n,\ttransform_name: \"" + Yetani::outputTransformName(output.transform) + "\""
10430  + "\n,\tflags: " + std::to_string(output.flags)
10431  + "\n,\twidth: " + std::to_string(output.width)
10432  + "\n,\theight: " + std::to_string(output.height)
10433  + "\n,\trefresh_mHz: " + std::to_string(output.refresh_mHz)
10434  + "\n,\tscale_factor: " + std::to_string(output.scale_factor)
10435  + "\n,\tpixels_per_mm_horizontal: " + std::to_string(output.pixels_per_mm_horizontal)
10436  + "\n,\tpixels_per_mm_vertical: " + std::to_string(output.pixels_per_mm_vertical)
10437  + "\n}";
10438 }
10439 
10440 
10448 std::string to_string(const Yetani::PointerAxisSource source
10449  ) noexcept
10450 {
10451  switch(source)
10452  {
10453  case Yetani::PointerAxisSource::Continuous: return "Continuous";
10454  case Yetani::PointerAxisSource::Finger: return "Finger";
10455  case Yetani::PointerAxisSource::Wheel: return "Wheel";
10456  case Yetani::PointerAxisSource::Wheel_Tilt: return "Wheel Tilt";
10457  case Yetani::PointerAxisSource::Unknown: [[fallthrough]];
10458  default: return "";
10459  }
10460 }
10461 
10462 
10470 std::string to_string(const Yetani::PointerAxisType type
10471  ) noexcept
10472 {
10473  switch(type)
10474  {
10475  case Yetani::PointerAxisType::Horizontal: return "Horizontal";
10476  case Yetani::PointerAxisType::Vertical: return "Vertical";
10477  case Yetani::PointerAxisType::Unknown: [[fallthrough]];
10478  default: return "";
10479  }
10480 }
10481 
10482 
10490 std::string to_string(const Yetani::PointerButtonState button_state
10491  ) noexcept
10492 {
10493  switch(button_state)
10494  {
10495  case Yetani::PointerButtonState::Pressed: return "Pressed";
10496  case Yetani::PointerButtonState::Released: return "Released";
10497  default: return "";
10498  }
10499 }
10500 
10501 
10509 std::string to_string(const Yetani::WindowMode window_mode
10510  ) noexcept
10511 {
10512  switch(window_mode)
10513  {
10514  case Yetani::WindowMode::Fullscreen: return "Fullscreen";
10515  case Yetani::WindowMode::Maximized: return "Maximized";
10516  case Yetani::WindowMode::Normal: return "Normal";
10517  default: return "";
10518  }
10519 }
10520 
10521 
10536  , Yetani::PointMm& rhs
10537  ) noexcept
10538 {
10539  return equalish(lhs.x, rhs.x, 0.001)
10540  && equalish(lhs.y, rhs.y, 0.001)
10541  ;
10542 }
10543 
10544 
10559  , Yetani::PointPercent& rhs
10560  ) noexcept
10561 {
10562  return equalish(lhs.x, rhs.x, 0.00001)
10563  && equalish(lhs.y, rhs.y, 0.00001)
10564  ;
10565 }
10566 
10567 
10579  , Yetani::PointPixel& rhs
10580  ) noexcept
10581 {
10582  return (lhs.x == rhs.x) && (lhs.y == rhs.y);
10583 }
10584 
10585 
10598  , Yetani::SizeMm& rhs
10599  ) noexcept
10600 {
10601  return equalish(lhs.width, rhs.width, 0.001)
10602  && equalish(lhs.height, rhs.height, 0.001)
10603  ;
10604 }
10605 
10606 
10619  , Yetani::SizePercent& rhs
10620  ) noexcept
10621 {
10622  return equalish(lhs.width, rhs.width, 0.00001)
10623  && equalish(lhs.height, rhs.height, 0.00001)
10624  ;
10625 }
10626 
10627 
10637  , Yetani::SizePixel& rhs
10638  ) noexcept
10639 {
10640  return (lhs.width == rhs.width) && (lhs.height == rhs.height);
10641 }
10642 
10643 // }}}
10644 
10645 };
10646 
10647 #endif // ZAKERO_YETANI_IMPLEMENTATION
10648 
10649 // }}}
10650 
10651 #endif // zakero_Yetani_h
zakero::MemoryPool::size
size_t size() const noexcept
The size of the memory pool.
Definition: Zakero_MemoryPool.h:740
zakero::Yetani::SizePixel::operator==
friend bool operator==(Yetani::SizePixel &, Yetani::SizePixel &) noexcept
Compare two Size objects.
Definition: Zakero_Yetani.h:10636
zakero::Yetani::Window::pointerOnAxis
void pointerOnAxis(Yetani::LambdaAxis) noexcept
Respond to "Pointer Axis" events.
Definition: Zakero_Yetani.h:10205
zakero::Yetani::Window::setTitle
void setTitle(const std::string &) noexcept
Change the window title.
Definition: Zakero_Yetani.h:8906
zakero::Yetani::Window::setClass
void setClass(const std::string &) noexcept
Change the window class.
Definition: Zakero_Yetani.h:8893
zakero::Yetani::Output::height
int32_t height
The height of the device in hardware units.
Definition: Zakero_Yetani.h:1194
zakero::Yetani::shmFormatDescription
static std::string shmFormatDescription(const wl_shm_format) noexcept
Get a description of the format.
Definition: Zakero_Yetani.h:4420
zakero::Yetani::PointerButton
Information about a pointer button event.
Definition: Zakero_Yetani.h:1120
zakero::Yetani::outputVector
Yetani::VectorOutputId outputVector() const noexcept
Get a list of the Output Id's.
Definition: Zakero_Yetani.h:4719
zakero::Yetani::keyRepeatDelay
int32_t keyRepeatDelay() const noexcept
The key repeat delay.
Definition: Zakero_Yetani.h:5430
zakero::Yetani::LambdaSizePixel
std::function< void(const Yetani::SizePixel &)> LambdaSizePixel
A Lambda that has a parameter: SizePixel.
Definition: Zakero_Yetani.h:1298
Zakero_Base.h
Zakero Base.
zakero::Yetani::PointPercent
A location that uses percentages.
Definition: Zakero_Yetani.h:1068
zakero::Yetani::LambdaKey
std::function< void(const Yetani::Key &, const Yetani::KeyModifier &)> LambdaKey
A Lambda that has parameters: Key and KeyModifier.
Definition: Zakero_Yetani.h:1285
zakero::Yetani::Window::Memory::memory_pool
zakero::MemoryPool memory_pool
The Window's Memory Pool.
Definition: Zakero_Yetani.h:1399
zakero::Yetani::LambdaPointPixel
std::function< void(const Yetani::PointPixel &, const Yetani::KeyModifier &)> LambdaPointPixel
A Lambda that has parameters: PointPixel and KeyModifier.
Definition: Zakero_Yetani.h:1292
zakero::Yetani::PointerAxis::steps
int32_t steps
The number of rotation steps.
Definition: Zakero_Yetani.h:1105
zakero::Yetani::keyRepeatRate
int32_t keyRepeatRate() const noexcept
The key repeat rate.
Definition: Zakero_Yetani.h:5444
zakero::Yetani::SizeMm::height
float height
The height.
Definition: Zakero_Yetani.h:1131
zakero::Yetani::Output::pixels_per_mm_horizontal
float pixels_per_mm_horizontal
A pre-calculated value.
Definition: Zakero_Yetani.h:1202
zakero::Yetani::Window::~Window
virtual ~Window()
Destroy a Window.
Definition: Zakero_Yetani.h:8796
zakero::Yetani::PointerAxisSource::Unknown
@ Unknown
Wheel Tilt.
zakero::Yetani::Output::subpixel
int32_t subpixel
The device's subpixel orientation.
Definition: Zakero_Yetani.h:1197
zakero::Yetani::CursorConfig
Cursor configuration.
Definition: Zakero_Yetani.h:1164
zakero::MemoryPool
A pool of memory.
Definition: Zakero_MemoryPool.h:264
zakero::Yetani::SizeMm::width
float width
The width.
Definition: Zakero_Yetani.h:1130
zakero::Yetani::outputConvertToPercent
Yetani::PointPercent outputConvertToPercent(const Yetani::OutputId, const Yetani::PointPixel &) const noexcept
Convert Pixel to a Percentage.
Definition: Zakero_Yetani.h:4824
zakero::Yetani::SizeMm
Size measured in millimeters.
Definition: Zakero_Yetani.h:1129
zakero::Yetani::Output::model
std::string model
Description of the model.
Definition: Zakero_Yetani.h:1190
zakero::Yetani::PointerAxisType
PointerAxisType
The direction of the axis movement.
Definition: Zakero_Yetani.h:1097
zakero::Yetani::Output::physical_height_mm
int32_t physical_height_mm
The height of the device in millimeters.
Definition: Zakero_Yetani.h:1196
zakero::Yetani::Output::scale_factor
int32_t scale_factor
The scaling factor between the device and compositor.
Definition: Zakero_Yetani.h:1199
zakero::Yetani::Key::time
uint32_t time
When the key event happened.
Definition: Zakero_Yetani.h:1036
zakero::Yetani::PointPercent::time
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1069
zakero::Yetani::Output::y
int32_t y
The Y position within the global compositor.
Definition: Zakero_Yetani.h:1192
zakero::Yetani::Window::cursorHide
void cursorHide() noexcept
Hide the cursor.
Definition: Zakero_Yetani.h:8858
zakero::Yetani::Window::onCloseRequest
void onCloseRequest(Yetani::Lambda) noexcept
Respond to "Close Request" events.
Definition: Zakero_Yetani.h:9651
zakero::Yetani::output
Yetani::Output output(const Yetani::OutputId) const noexcept
Get a copy of the Output information.
Definition: Zakero_Yetani.h:4687
zakero::MemoryPool::sizeOnChange
void sizeOnChange(MemoryPool::LambdaSize) noexcept
Set the Size Event callback.
Definition: Zakero_MemoryPool.h:775
zakero::Yetani::outputConvertToMm
Yetani::PointMm outputConvertToMm(const Yetani::OutputId, const Yetani::PointPixel &) const noexcept
Convert Pixel to Millimeter.
Definition: Zakero_Yetani.h:4794
zakero::Yetani::SizePercent::width
float width
The width.
Definition: Zakero_Yetani.h:1138
zakero::Yetani::Window::Window
Window(void *)
Construct a Window.
Definition: Zakero_Yetani.h:8742
zakero::Yetani::outputSubpixelName
static std::string outputSubpixelName(int32_t) noexcept
Get a human readable string.
Definition: Zakero_Yetani.h:4745
zakero::Yetani::Output::x
int32_t x
The X position within the global compositor.
Definition: Zakero_Yetani.h:1191
zakero::Yetani::LambdaAxis
std::function< void(const Yetani::PointerAxis &, const Yetani::KeyModifier &)> LambdaAxis
A Lambda that has parameters: PointerAxis and KeyModifier.
Definition: Zakero_Yetani.h:1286
zakero::Yetani::PointerAxisType::Unknown
@ Unknown
Vertical.
zakero::Yetani::shmFormatName
static std::string shmFormatName(const wl_shm_format) noexcept
Get the name of the format.
Definition: Zakero_Yetani.h:4443
zakero::Yetani::Window::windowMode
Yetani::WindowMode windowMode() noexcept
Get the current WindowMode.
Definition: Zakero_Yetani.h:8960
zakero::Yetani::Output::width
int32_t width
The width of the device in hardware units.
Definition: Zakero_Yetani.h:1193
zakero::Yetani::Window::cursorShow
void cursorShow() noexcept
Show the cursor.
Definition: Zakero_Yetani.h:8869
zakero::Yetani::Output::flags
uint32_t flags
Device flags.
Definition: Zakero_Yetani.h:1201
zakero::Yetani::PointPixel::y
int32_t y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1080
zakero::Yetani::Window::windowModeIs
bool windowModeIs(const Yetani::WindowMode) noexcept
Check the WindowMode.
Definition: Zakero_Yetani.h:8978
zakero::Yetani::KeyModifier::locked
uint32_t locked
A collection of locked modifiers.
Definition: Zakero_Yetani.h:1051
zakero::MemoryPool::fd
int fd() const noexcept
The backing file descriptor.
Definition: Zakero_MemoryPool.h:727
zakero::Yetani::Window::keyboardOnLeave
void keyboardOnLeave(Yetani::Lambda) noexcept
Respond to "Keyboard Leave" events.
Definition: Zakero_Yetani.h:9752
zakero::Yetani::LambdaBool
std::function< void(bool)> LambdaBool
A Lambda that has a parameter: bool.
Definition: Zakero_Yetani.h:1293
zakero::Yetani::SizePercent::height
float height
The height.
Definition: Zakero_Yetani.h:1139
zakero::Yetani::Window::windowModeSet
void windowModeSet(const Yetani::WindowMode) noexcept
Change the window mode.
Definition: Zakero_Yetani.h:9002
zakero::Yetani::KeyModifier
A collection modifier flags.
Definition: Zakero_Yetani.h:1048
zakero::Yetani::PointerButton::code
uint32_t code
The event code.
Definition: Zakero_Yetani.h:1121
zakero::Yetani::Window::imageNext
std::error_code imageNext(uint8_t *&, Yetani::SizePixel &) noexcept
Get an image buffer.
Definition: Zakero_Yetani.h:9347
zakero::Yetani::WindowDecorations
WindowDecorations
Who is responsible for rendering the decorations.
Definition: Zakero_Yetani.h:1272
zakero::Yetani::outputOnChange
void outputOnChange(Yetani::LambdaOutputId) noexcept
Notification that an Output device has changed.
Definition: Zakero_Yetani.h:5054
zakero::Yetani::Key
Key event information.
Definition: Zakero_Yetani.h:1035
zakero::Yetani::Window::convertToPixel
Yetani::PointPixel convertToPixel(const Yetani::PointMm &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9507
zakero::Yetani::Window::keyboardOnKey
void keyboardOnKey(Yetani::LambdaKey) noexcept
Respond to "Keyboard Key" events.
Definition: Zakero_Yetani.h:9780
zakero::Yetani::cursorDestroy
std::error_code cursorDestroy(const std::string &) noexcept
Destroy a cursor.
Definition: Zakero_Yetani.h:3891
zakero::Yetani::KeyModifier_Shift
static constexpr uint32_t KeyModifier_Shift
Key Modifier flag.
Definition: Zakero_Yetani.h:1045
zakero::Yetani::LambdaSizePercent
std::function< void(const Yetani::SizePercent &)> LambdaSizePercent
A Lambda that has a parameter: SizePercent.
Definition: Zakero_Yetani.h:1297
zakero::Yetani::WindowMode::Normal
@ Normal
A window that uses as much of the screen as possible.
zakero::Yetani::PointMm::time
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1060
zakero::Yetani::PointPixel::x
int32_t x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1079
zakero::Yetani::LambdaPointMm
std::function< void(const Yetani::PointMm &, const Yetani::KeyModifier &)> LambdaPointMm
A Lambda that has parameters: PointMm and KeyModifier.
Definition: Zakero_Yetani.h:1290
zakero::Yetani::PointerButtonState
PointerButtonState
Mouse button state.
Definition: Zakero_Yetani.h:1115
zakero::Yetani::KeyModifier_CapsLock
static constexpr uint32_t KeyModifier_CapsLock
Key Modifier flag.
Definition: Zakero_Yetani.h:1042
zakero::Yetani::Window::pointerOnLeave
void pointerOnLeave(Yetani::Lambda) noexcept
Respond to "Pointer Leave" events.
Definition: Zakero_Yetani.h:10094
zakero::Yetani::SizeMm::operator==
friend bool operator==(Yetani::SizeMm &, Yetani::SizeMm &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10597
zakero::Yetani::KeyModifier::latched
uint32_t latched
A collection of latched modifiers.
Definition: Zakero_Yetani.h:1050
zakero::Yetani::shmFormatAvailable
const Yetani::VectorShmFormat & shmFormatAvailable() const noexcept
Get all the support color formats.
Definition: Zakero_Yetani.h:4378
zakero::Yetani::KeyModifier_Meta
static constexpr uint32_t KeyModifier_Meta
Key Modifier flag.
Definition: Zakero_Yetani.h:1044
zakero::Yetani::Window::cursorUse
std::error_code cursorUse(const std::string &) noexcept
Use a cursor.
Definition: Zakero_Yetani.h:8841
zakero::Yetani::shmFormatBytesPerPixel
static uint8_t shmFormatBytesPerPixel(const wl_shm_format) noexcept
Determine bytes-per-pixel.
Definition: Zakero_Yetani.h:4395
zakero::Yetani::KeyState
KeyState
Keyboard key state
Definition: Zakero_Yetani.h:1029
zakero::Yetani::PointPercent::operator==
friend bool operator==(Yetani::PointPercent &, Yetani::PointPercent &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10558
zakero::Yetani::WindowDecorations::Client_Side
@ Client_Side
The Wayland Compositor will draw the decorations.
zakero::Yetani::PointerAxis::distance
float distance
The distance traveled.
Definition: Zakero_Yetani.h:1106
zakero::Yetani::PointerAxis::source
Yetani::PointerAxisSource source
The source of the event.
Definition: Zakero_Yetani.h:1107
zakero::Yetani::Window::convertToMm
Yetani::PointMm convertToMm(const Yetani::PointPixel &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9461
zakero::Yetani::Output::refresh_mHz
int32_t refresh_mHz
The current refresh rate of the device.
Definition: Zakero_Yetani.h:1198
zakero::convert
double convert(const double size, const zakero::Storage from, const zakero::Storage to) noexcept
Convert storage sizes.
Definition: Zakero_Base.h:234
zakero::Yetani::outputTransformName
static std::string outputTransformName(int32_t) noexcept
Get a human readable string.
Definition: Zakero_Yetani.h:4770
zakero::Yetani::PointPixel::operator==
friend bool operator==(Yetani::PointPixel &, Yetani::PointPixel &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10578
zakero::Yetani::PointerAxisSource
PointerAxisSource
Where the axis information came from.
Definition: Zakero_Yetani.h:1089
zakero::Yetani::PointPercent::y
float y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1071
zakero::Yetani::PointPercent::x
float x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1070
zakero::Yetani::PointMm
A location that uses millimeters.
Definition: Zakero_Yetani.h:1059
zakero::Yetani::Window::onFocusChange
void onFocusChange(Yetani::LambdaBool) noexcept
Respond to "Active" change events.
Definition: Zakero_Yetani.h:9705
Zakero_MemoryPool.h
Zakero MemoryPool.
zakero::Yetani::LambdaButtonPixel
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:1289
zakero::Yetani::Window::pointerOnAxisDiscrete
void pointerOnAxisDiscrete(Yetani::Lambda) noexcept
Respond to "Pointer Axis Discrete" events.
Definition: Zakero_Yetani.h:10286
ZAKERO_STEADY_TIME_NOW
#define ZAKERO_STEADY_TIME_NOW(unit_)
Get the current time.
Definition: Zakero_Base.h:121
zakero::Yetani::KeyModifier_Control
static constexpr uint32_t KeyModifier_Control
Key Modifier flag.
Definition: Zakero_Yetani.h:1043
zakero::Yetani::Window::pointerOnMotion
void pointerOnMotion(Yetani::LambdaPointMm) noexcept
Respond to "Pointer Motion" events.
Definition: Zakero_Yetani.h:10122
zakero::Yetani::windowCreate
Yetani::Window * windowCreate(const Yetani::SizeMm &, std::error_code &) noexcept
Create a window.
Definition: Zakero_Yetani.h:8006
zakero::to_string
std::string to_string(const std::error_code &error) noexcept
Convert an std::error_code to a std::string.
Definition: Zakero_Base.h:353
zakero::Yetani::LambdaSizeMm
std::function< void(const Yetani::SizeMm &)> LambdaSizeMm
A Lambda that has a parameter: SizeMm.
Definition: Zakero_Yetani.h:1296
zakero::Yetani::LambdaButtonPercent
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:1288
zakero::MemoryPool::init
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:633
zakero::Yetani::Output::physical_width_mm
int32_t physical_width_mm
The width of the device in millimeters.
Definition: Zakero_Yetani.h:1195
zakero::Yetani::PointMm::x
float x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1061
zakero::Yetani::SizePercent::operator==
friend bool operator==(Yetani::SizePercent &, Yetani::SizePercent &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10618
zakero::Yetani::Window::onDecorationsChange
void onDecorationsChange(Yetani::LambdaWindowDecorations) noexcept
Respond to "Decoration Change" events.
Definition: Zakero_Yetani.h:9676
zakero::Yetani::PointMm::y
float y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1062
zakero::Yetani::connect
static Yetani * connect() noexcept
Establish a connection with the Wayland Compositor.
Definition: Zakero_Yetani.h:3270
zakero::Yetani::Key::code
uint32_t code
The key code of the event.
Definition: Zakero_Yetani.h:1037
zakero::Yetani::Lambda
std::function< void()> Lambda
A Lambda that has no parameters.
Definition: Zakero_Yetani.h:1284
zakero::Yetani::PointerAxis
Information about an Axis event.
Definition: Zakero_Yetani.h:1103
zakero::Yetani::cursorCreate
std::error_code cursorCreate(const std::string &, const Yetani::CursorConfig &) noexcept
Create a cursor.
Definition: Zakero_Yetani.h:3753
zakero::Yetani::PointPixel
A location that uses pixels.
Definition: Zakero_Yetani.h:1077
zakero::Yetani::KeyModifier::pressed
uint32_t pressed
A collection of pressed modifiers.
Definition: Zakero_Yetani.h:1049
zakero::Yetani::Window::pointerOnAxisStop
void pointerOnAxisStop(Yetani::Lambda) noexcept
Respond to "Pointer Axis Stop" events.
Definition: Zakero_Yetani.h:10259
zakero::Yetani::Output::pixels_per_mm_vertical
float pixels_per_mm_vertical
A pre-calculated value.
Definition: Zakero_Yetani.h:1203
zakero::Yetani::Output::transform
int32_t transform
Transform that maps framebuffer to output.
Definition: Zakero_Yetani.h:1200
zakero::Yetani::Window::keyboardOnEnter
void keyboardOnEnter(Yetani::Lambda) noexcept
Respond to "Keyboard Enter" events.
Definition: Zakero_Yetani.h:9726
zakero::Yetani::LambdaButtonMm
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:1287
zakero::Yetani
A wrapper class for Wayland.
Definition: Zakero_Yetani.h:1017
zakero::vectorContains
bool vectorContains(const std::vector< Type > &vector, const Type &value) noexcept
Check the contents of a std::vector.
Definition: Zakero_Base.h:267
zakero::Yetani::PointerButtonState::Released
@ Released
Pressed.
zakero::Yetani::SizePixel::width
int32_t width
The width.
Definition: Zakero_Yetani.h:1146
zakero::operator==
bool operator==(Yetani::PointMm &lhs, Yetani::PointMm &rhs) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10535
zakero::Yetani::Window::convertToPercent
Yetani::PointPercent convertToPercent(const Yetani::PointPixel &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9484
zakero::Yetani::Window::onSizeChange
void onSizeChange(Yetani::LambdaSizeMm) noexcept
Respond to "Resize" events.
Definition: Zakero_Yetani.h:9836
zakero::Yetani::PointMm::operator==
friend bool operator==(Yetani::PointMm &, Yetani::PointMm &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10535
zakero::Yetani::outputOnRemove
void outputOnRemove(Yetani::LambdaOutputId) noexcept
Notification of removing an Output device.
Definition: Zakero_Yetani.h:5077
zakero::Yetani::PointerButton::state
Yetani::PointerButtonState state
The button state.
Definition: Zakero_Yetani.h:1122
zakero::Yetani::Window::setDecorations
std::error_code setDecorations(const Yetani::WindowDecorations) noexcept
Use the Desktop Environment borders.
Definition: Zakero_Yetani.h:8932
zakero::Yetani::KeyModifier_Alt
static constexpr uint32_t KeyModifier_Alt
Key Modifier flag.
Definition: Zakero_Yetani.h:1041
zakero::Yetani::CursorConfig::image_data
const std::vector< void * > & image_data
A collection of image data.
Definition: Zakero_Yetani.h:1170
zakero::Yetani::Window::time
uint32_t time() const noexcept
When the last frame was rendered.
Definition: Zakero_Yetani.h:9415
zakero::Yetani::Window::minimize
void minimize() noexcept
Minimize the window.
Definition: Zakero_Yetani.h:9446
zakero::Yetani::Window::Memory::wl_shm_pool
struct wl_shm_pool * wl_shm_pool
A pointer to the Wayland Shared Memory Pool.
Definition: Zakero_Yetani.h:1398
zakero::Yetani::Window
A Window.
Definition: Zakero_Yetani.h:1303
zakero::Yetani::SizePixel
Size measured in pixels.
Definition: Zakero_Yetani.h:1145
zakero::Yetani::Key::state
KeyState state
The state of the key.
Definition: Zakero_Yetani.h:1038
zakero::Yetani::Window::setSizeMinMax
std::error_code setSizeMinMax(const Yetani::SizeMm &, const Yetani::SizeMm &) noexcept
Set the minimum window size.
Definition: Zakero_Yetani.h:9186
zakero::Yetani::Output
Information about a output device.
Definition: Zakero_Yetani.h:1188
zakero::Yetani::Window::setSize
std::error_code setSize(const Yetani::SizeMm &) noexcept
Set the window size.
Definition: Zakero_Yetani.h:9048
zakero::Yetani::Window::pointerOnButton
void pointerOnButton(Yetani::LambdaButtonMm) noexcept
Respond to "Pointer Button" events.
Definition: Zakero_Yetani.h:9917
zakero::Yetani::WindowMode
WindowMode
Definition: Zakero_Yetani.h:1277
zakero::Yetani::SHM_FORMAT_DEFAULT
static constexpr wl_shm_format SHM_FORMAT_DEFAULT
The default pixel format.
Definition: Zakero_Yetani.h:1418
zakero::Yetani::KeyModifier::group
uint32_t group
The keyboard layout.
Definition: Zakero_Yetani.h:1052
zakero::Yetani::Window::pointerOnEnter
void pointerOnEnter(Yetani::LambdaPointMm) noexcept
Respond to "Pointer Enter" events.
Definition: Zakero_Yetani.h:10004
zakero::Yetani::Window::windowModeOnChange
void windowModeOnChange(Yetani::LambdaWindowMode) noexcept
Respond to "Window Mode" events.
Definition: Zakero_Yetani.h:9807
zakero::Yetani::PointPixel::time
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1078
zakero::Yetani::LambdaWindowDecorations
std::function< void(Yetani::WindowDecorations)> LambdaWindowDecorations
A Lambda that has a parameter: WindowDecorations.
Definition: Zakero_Yetani.h:1294
zakero::Yetani::~Yetani
virtual ZAKERO_YETANI__ERROR_DATA ~Yetani() noexcept
Destructor.
Definition: Zakero_Yetani.h:3234
zakero::Yetani::SizePercent
Size measured as a percentage of the Output (Monitor) resolution.
Definition: Zakero_Yetani.h:1137
zakero::Yetani::PointerAxis::time
uint32_t time
When the event occurred.
Definition: Zakero_Yetani.h:1104
zakero::Yetani::Window::pointerOnAxisSource
void pointerOnAxisSource(Yetani::Lambda) noexcept
Respond to "Pointer Axis Source" events.
Definition: Zakero_Yetani.h:10232
zakero::Yetani::Window::imagePresent
void imagePresent() noexcept
Render the image.
Definition: Zakero_Yetani.h:9383
zakero::Yetani::LambdaPointPercent
std::function< void(const Yetani::PointPercent &, const Yetani::KeyModifier &)> LambdaPointPercent
A Lambda that has parameters: PointPercent and KeyModifier.
Definition: Zakero_Yetani.h:1291
zakero::Yetani::Output::make
std::string make
Description of the manufacturer.
Definition: Zakero_Yetani.h:1189
zakero::Yetani::SizePixel::height
int32_t height
The height.
Definition: Zakero_Yetani.h:1147
zakero::vectorErase
auto vectorErase(std::vector< Type > &vector, const Type &value) noexcept
Erase the contents of a std::vector.
Definition: Zakero_Base.h:338
zakero::Yetani::PointerAxis::type
Yetani::PointerAxisType type
The type of Axis.
Definition: Zakero_Yetani.h:1108
zakero::Yetani::Window::Memory
The shared memory.
Definition: Zakero_Yetani.h:1397
zakero::Yetani::Window::bytesPerPixel
uint8_t bytesPerPixel() const noexcept
Get the number of bytes per pixel.
Definition: Zakero_Yetani.h:9433
zakero::Yetani::outputOnAdd
void outputOnAdd(Yetani::LambdaOutputId) noexcept
Notification of adding an Output device.
Definition: Zakero_Yetani.h:5031
zakero::Yetani::LambdaWindowMode
std::function< void(Yetani::WindowMode)> LambdaWindowMode
A Lambda that has a parameter: WindowMode.
Definition: Zakero_Yetani.h:1295
zakero::Yetani::outputConvertToPixel
Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointMm &) const noexcept
Convert Millimeter to Pixel.
Definition: Zakero_Yetani.h:4854