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;
1038  KeyState state;
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 
1047  struct KeyModifier
1048  {
1049  uint32_t pressed;
1050  uint32_t latched;
1051  uint32_t locked;
1052  uint32_t group;
1053  };
1055  // }}}
1056  // {{{ Type : Point
1057 
1058  struct PointMm
1059  {
1060  uint32_t time;
1061  float x;
1062  float y;
1064  friend bool operator==(Yetani::PointMm&, Yetani::PointMm&) noexcept;
1065  };
1066 
1068  {
1069  uint32_t time;
1070  float x;
1071  float y;
1072 
1074  };
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  };
1085  // }}}
1086  // {{{ Type : Pointer Axis
1088  enum struct PointerAxisSource
1089  { Unknown
1090  , Continuous
1091  , Finger
1092  , Wheel
1094  };
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 
1119  struct PointerButton
1120  {
1121  uint32_t code;
1123  };
1124 
1125  // }}}
1126  // {{{ Type : Size
1127 
1128  struct SizeMm
1129  {
1130  float width;
1131  float height;
1133  friend bool operator==(Yetani::SizeMm&, Yetani::SizeMm&) noexcept;
1134  };
1135 
1136  struct SizePercent
1137  {
1138  float width;
1139  float height;
1141  friend bool operator==(Yetani::SizePercent&, Yetani::SizePercent&) noexcept;
1142  };
1143 
1144  struct SizePixel
1145  {
1146  int32_t width;
1147  int32_t height;
1149  friend bool operator==(Yetani::SizePixel&, Yetani::SizePixel&) noexcept;
1150  };
1151 
1152  // }}}
1153  // {{{ Connection
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
1163  struct CursorConfig
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  };
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>;
1214  // -------------------------------------------------- //
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;
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;
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)>;
1294  using LambdaWindowDecorations = std::function<void(Yetani::WindowDecorations)>;
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;
1320  uint8_t bytesPerPixel() const noexcept;
1322  // }}}
1323  // {{{ Window Mode
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;
1343  Yetani::PointPercent convertToPercent(const Yetani::PointPixel&) const noexcept;
1344  Yetani::PointPixel convertToPixel(const Yetani::PointMm&) const noexcept;
1345  Yetani::PointPixel convertToPixel(const Yetani::PointPercent&) const noexcept;
1346 
1347  Yetani::SizeMm convertToMm(const Yetani::SizePixel&) const noexcept;
1348  Yetani::SizePercent convertToPercent(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;
1370  void pointerOnEnter(Yetani::LambdaPointPercent) noexcept;
1371  void pointerOnEnter(Yetani::LambdaPointPixel) noexcept;
1372  void pointerOnLeave(Yetani::Lambda) noexcept;
1373  void pointerOnMotion(Yetani::LambdaPointMm) noexcept;
1374  void pointerOnMotion(Yetani::LambdaPointPercent) noexcept;
1375  void pointerOnMotion(Yetani::LambdaPointPixel) noexcept;
1376  void pointerOnButton(Yetani::LambdaButtonMm) noexcept;
1377  void pointerOnButton(Yetani::LambdaButtonPercent) noexcept;
1378  void pointerOnButton(Yetani::LambdaButtonPixel) 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  {
1398  struct wl_shm_pool* wl_shm_pool;
1399  zakero::MemoryPool memory_pool;
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 
1413  // -------------------------------------------------- //
1414 
1415  static constexpr wl_shm_format SHM_FORMAT_DEFAULT = WL_SHM_FORMAT_XRGB8888;
1416 
1417  // -------------------------------------------------- //
1418 
1419  Yetani::Window* windowCreate(const Yetani::SizeMm&, std::error_code&) noexcept;
1420  Yetani::Window* windowCreate(const Yetani::SizeMm&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1421  Yetani::Window* windowCreate(const Yetani::SizeMm&, const wl_shm_format, std::error_code&) noexcept;
1422  Yetani::Window* windowCreate(const Yetani::SizePercent&, std::error_code&) noexcept;
1423  Yetani::Window* windowCreate(const Yetani::SizePercent&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1424  Yetani::Window* windowCreate(const Yetani::SizePercent&, const wl_shm_format, std::error_code&) noexcept;
1425  Yetani::Window* windowCreate(const Yetani::SizePixel&, std::error_code&) noexcept;
1426  Yetani::Window* windowCreate(const Yetani::SizePixel&, const wl_shm_format = SHM_FORMAT_DEFAULT) noexcept;
1427  Yetani::Window* windowCreate(const Yetani::SizePixel&, const wl_shm_format, std::error_code&) noexcept;
1428 
1429  // }}}
1430 
1431  private:
1432  static constexpr uint32_t Size_Max = (uint32_t)std::numeric_limits<int32_t>::max();
1433 
1434  Yetani() noexcept;
1435 
1436  // {{{ Type
1437 
1438  using VectorWlSurface = std::vector<struct wl_surface*>;
1439 
1440  // }}}
1441  // {{{ Connection
1442 
1443  void disconnect() noexcept;
1444 
1445  // }}}
1446  // {{{ Cursor
1447 
1448  struct Cursor
1449  {
1450  struct wl_surface* wl_surface;
1451  std::vector<::wl_buffer*> buffer_vector;
1452  wl_shm_format format;
1453  int64_t next_frame_time;
1454  size_t buffer_index;
1455  uint32_t time_per_frame;
1456  int32_t width;
1457  int32_t height;
1458  int32_t hotspot_x;
1459  int32_t hotspot_y;
1460  };
1461 
1462  using MapStringCursor = std::unordered_map<std::string, Yetani::Cursor>;
1463 
1464  MapStringCursor cursor_map;
1465 
1466  // -------------------------------------------------- //
1467 
1468  struct CursorSurface
1469  {
1470  struct wl_pointer* wl_pointer;
1471  struct wl_surface* wl_surface;
1472  uint32_t serial;
1473  int32_t hotspot_x;
1474  int32_t hotspot_y;
1475  bool is_visible;
1476  };
1477 
1478  using MapCursorSurface = std::unordered_map<struct wl_surface*, Yetani::CursorSurface>;
1479 
1480  MapCursorSurface cursor_surface_map;
1481 
1482  // -------------------------------------------------- //
1483 
1484  zakero::MemoryPool cursor_memory_pool;
1485  mutable std::mutex cursor_mutex;
1486  struct wl_shm_pool* cursor_shm_pool;
1487  struct wl_pointer* cursor_pointer;
1488 
1489  // -------------------------------------------------- //
1490 
1491  void cursorAnimate() noexcept;
1492  std::error_code cursorCreateCursor(const std::string&, const Yetani::CursorConfig&) noexcept;
1493  void cursorEnter(struct wl_pointer*, uint32_t, struct wl_surface*) noexcept;
1494  void cursorLeave(struct wl_surface*) noexcept;
1495  void cursorHide(struct wl_surface*) noexcept;
1496  void cursorShow(struct wl_surface*) noexcept;
1497  bool cursorIsHidden(struct wl_surface*) const noexcept;
1498  void cursorSetup() noexcept;
1499  void cursorTeardown() noexcept;
1500  std::error_code cursorAttach(const std::string&, struct wl_surface*) noexcept;
1501  std::error_code cursorDetach(struct wl_surface*) noexcept;
1502 
1503  // }}}
1504  // {{{ Event Loop
1505 
1506  std::jthread event_loop;
1507  std::atomic<bool> event_loop_is_running;
1508 
1509  // -------------------------------------------------- //
1510 
1511  void eventLoopStart() noexcept;
1512  static void eventLoop(std::stop_token, Yetani*) noexcept;
1513 
1514  // }}}
1515  // {{{ Wayland
1516 
1517  struct wl_compositor* compositor;
1518  struct wl_display* display;
1519  struct wl_registry* registry;
1520  struct wl_shm* shm;
1521  Yetani::VectorShmFormat shm_format_vector;
1522 
1523  // }}}
1524  // {{{ Wayland : Seat
1525 
1526  struct Seat
1527  {
1528  struct wl_keyboard* wl_keyboard = nullptr;
1529  struct wl_pointer* wl_pointer = nullptr;
1530  struct wl_touch* wl_touch = nullptr;
1531  std::string name = "";
1532  uint32_t version = 0;
1533  };
1534 
1535  using MapSeat = std::map<struct wl_seat*, Seat>;
1536  using MapIdWlSeat = std::map<uint32_t, struct wl_seat*>;
1537 
1538  Yetani::MapSeat seat_map;
1539  Yetani::MapIdWlSeat id_to_seat;
1540 
1541  // -------------------------------------------------- //
1542 
1543  struct wl_seat* seat;
1544 
1545  // -------------------------------------------------- //
1546 
1547  void seatDestroy(struct wl_seat*&) noexcept;
1548 
1549  // }}}
1550  // {{{ Wayland : Seat : Keyboard
1551 
1552  struct KeyRepeatData
1553  {
1554  std::chrono::time_point<std::chrono::steady_clock> trigger_time;
1555  uint32_t base_time;
1556  };
1557 
1558  using KeyRepeatMap = std::map<uint32_t, Yetani::KeyRepeatData>;
1559 
1560  // -------------------------------------------------- //
1561 
1562  struct KeyboardEvent
1563  {
1564  Yetani::Lambda on_enter;
1565  Yetani::Lambda on_leave;
1566  Yetani::LambdaKey on_key;
1567  };
1568 
1569  using MapKeyboardEvent = std::unordered_map<struct wl_surface*, Yetani::KeyboardEvent>;
1570 
1571  // -------------------------------------------------- //
1572 
1573  struct Keyboard
1574  {
1575  struct wl_surface* wl_surface = nullptr;
1576  Yetani::KeyboardEvent* event = nullptr;
1577  Yetani::MapKeyboardEvent event_map = {};
1578  Yetani::KeyModifier modifier = { 0 };
1579  Yetani::KeyRepeatMap repeat_map = {};
1580  char* keymap = nullptr;
1581  uint32_t keymap_size = 0;
1582  int32_t repeat_delay = 0;
1583  int32_t repeat_rate = 0;
1584  };
1585 
1586  Yetani::Keyboard keyboard;
1587 
1588  // -------------------------------------------------- //
1589 
1590  static void keyboardDestroy(Yetani::Keyboard&) noexcept;
1591  static void keyboardRepeat(Yetani::Keyboard&) noexcept;
1592  static void keyboardRepeatAdd(Yetani::Keyboard&, uint32_t, uint32_t) noexcept;
1593  static void keyboardRepeatReleaseAll(Yetani::Keyboard&) noexcept;
1594  static void keyboardRepeatRemove(Yetani::Keyboard&, uint32_t) noexcept;
1595 
1596  // }}}
1597  // {{{ Wayland : Seat : Pointer
1598 
1599  struct PointerEvent
1600  {
1601  Yetani::LambdaAxis on_axis;
1602  Yetani::Lambda on_axis_discrete;
1603  Yetani::Lambda on_axis_source;
1604  Yetani::Lambda on_axis_stop;
1605  Yetani::LambdaButtonMm on_button_mm;
1606  Yetani::LambdaButtonPercent on_button_percent;
1607  Yetani::LambdaButtonPixel on_button_pixel;
1608  Yetani::LambdaPointMm on_enter_mm;
1609  Yetani::LambdaPointPercent on_enter_percent;
1610  Yetani::LambdaPointPixel on_enter_pixel;
1611  Yetani::Lambda on_leave;
1612  Yetani::LambdaPointMm on_motion_mm;
1613  Yetani::LambdaPointPercent on_motion_percent;
1614  Yetani::LambdaPointPixel on_motion_pixel;
1615  };
1616 
1617  using MapPointerEvent = std::unordered_map<struct wl_surface*, Yetani::PointerEvent>;
1618 
1619  // -------------------------------------------------- //
1620 
1621  struct Pointer
1622  {
1623  // --- Common --- //
1624  Yetani* yetani = nullptr;
1625  struct wl_surface* wl_surface = nullptr;
1626  struct wl_pointer* wl_pointer = nullptr;
1627  Yetani::PointerEvent* event = nullptr;
1628  Yetani::MapPointerEvent event_map = {};
1629 
1630  // --- Processed Data --- //
1631  Yetani::PointMm point_mm = {};
1632  Yetani::PointPercent point_percent = {};
1633  Yetani::PointPixel point_pixel = {};
1634 
1635  // --- Axis --- //
1636  Yetani::PointerAxis axis = {};
1637 
1638  // --- Button --- //
1639  Yetani::PointerButton button = {};
1640  uint32_t button_event_code = 0;
1641  bool button_is_pressed = false;
1642  uint32_t button_time = {};
1643 
1644  // --- Enter --- //
1645  struct wl_surface* enter_surface = nullptr;
1646  Yetani::PointPixel enter_point = {};
1647  uint32_t enter_serial = 0;
1648 
1649  // --- Leave --- //
1650  struct wl_surface* leave_surface = nullptr;
1651 
1652  // --- Motion --- //
1653  Yetani::PointPixel motion_point = {};
1654  };
1655 
1656  Yetani::Pointer pointer;
1657 
1658  // -------------------------------------------------- //
1659 
1660  static void pointerClear(struct Pointer&) noexcept;
1661 
1662  // }}}
1663  // {{{ Wayland : Output
1664 
1665  enum struct OutputState
1666  { Done
1667  , Added
1668  , Changed
1669  };
1670 
1671  // -------------------------------------------------- //
1672 
1673  using VectorWlOutput = std::vector<struct wl_output*>;
1674 
1675  using MapWlOutputOutputState = std::unordered_map<struct wl_output*, Yetani::OutputState>;
1676  using MapOutputIdWlOutput = std::unordered_map<Yetani::OutputId, struct wl_output*>;
1677  using MapWlOutputOutputId = std::unordered_map<struct wl_output*, Yetani::OutputId>;
1678  using MapWlSurfaceVectorWlOutput = std::unordered_map<struct wl_surface*, Yetani::VectorWlOutput>;
1679  using MapWlOutputOutput = std::unordered_map<struct wl_output*, Output>;
1680 
1681  // -------------------------------------------------- //
1682 
1683  struct OutputData
1684  {
1685  Yetani::MapWlSurfaceVectorWlOutput surface_output_map = {};
1686  Yetani::MapOutputIdWlOutput outputid_to_wloutput = {};
1687  Yetani::MapWlOutputOutput output_map = {};
1688  Yetani::MapWlOutputOutputId wloutput_to_outputid = {};
1689  mutable std::mutex mutex = {};
1690  };
1691 
1692  Yetani::OutputData output_data;
1693 
1694  // -------------------------------------------------- //
1695 
1696  Yetani::LambdaOutputId on_output_add;
1697  Yetani::LambdaOutputId on_output_change;
1698  Yetani::LambdaOutputId on_output_remove;
1699 
1700  Yetani::MapWlOutputOutput output_changes_map;
1701  Yetani::MapWlOutputOutputState output_state_map;
1702 
1703  Yetani::VectorWlSurface output_notify_surface_vector;
1704 
1705  // -------------------------------------------------- //
1706 
1707  void convertPixel(struct wl_surface*, const int32_t, const int32_t, float&, float&, float&, float&) const noexcept;
1708 
1709  std::pair<float, float> convertPixelToMm(const Yetani::Output&, int32_t, int32_t) const noexcept;
1710  std::pair<float, float> convertPixelToPercent(const Yetani::Output&, int32_t, int32_t) const noexcept;
1711  std::pair<int32_t, int32_t> convertMmToPixel(const Yetani::Output&, float, float) const noexcept;
1712  std::pair<int32_t, int32_t> convertPercentToPixel(const Yetani::Output&, float, float) const noexcept;
1713 
1714  static void outputNotifySurface(Yetani*, struct wl_output*, struct wl_surface*) noexcept;
1715 
1716  // }}}
1717  // {{{ Wayland : Buffer
1718 
1719  struct SurfaceSize;
1720 
1721  struct BufferData
1722  {
1723  MemoryPool* memory_pool;
1724  off_t offset;
1725  };
1726 
1727  using MapBufferData = std::unordered_map<struct wl_buffer*, BufferData>;
1728 
1729  // -------------------------------------------------- //
1730 
1731  struct Buffer
1732  {
1733  MapBufferData map;
1734  std::mutex mutex;
1735  };
1736 
1737  Buffer buffer;
1738 
1739  // -------------------------------------------------- //
1740 
1741  static wl_buffer* bufferCreate(Yetani::SurfaceSize&, Yetani::Window::Memory*, Yetani::Buffer*) noexcept;
1742  static wl_buffer* bufferCreateAndRelease(Yetani*, Yetani::SurfaceSize&, Yetani::Window::Memory*) noexcept;
1743  static void bufferDestroy(struct wl_buffer*&) noexcept;
1744 
1745  // }}}
1746  // {{{ Wayland : Surface
1747 
1748  struct SurfaceEvent
1749  {
1750  Yetani::LambdaSizeMm on_size_mm_change;
1751  Yetani::LambdaSizePercent on_size_percent_change;
1752  Yetani::LambdaSizePixel on_size_pixel_change;
1753  };
1754 
1755  using MapSurfaceEvent = std::map<struct wl_surface*, Yetani::SurfaceEvent>;
1756 
1757  MapSurfaceEvent surface_event_map;
1758 
1759  // -------------------------------------------------- //
1760 
1761  enum struct SizeUnit
1762  { Millimeter
1763  , Percent
1764  , Pixel
1765  };
1766 
1767  // This is the data that needs to be locked from resizing
1768  // Use mainly by XdgSurface related methods
1769  struct SurfaceExtent
1770  {
1771  Yetani::SizeUnit preferred_unit;
1772  Yetani::SizeMm preferred_mm;
1773  Yetani::SizePercent preferred_percent;
1774  Yetani::SizeMm size_mm;
1775  Yetani::SizePercent size_percent;
1776  Yetani::SizePixel size_pixel;
1777  Yetani::SizePixel size_pixel_max;
1778  Yetani::SizePixel size_pixel_min;
1779  };
1780 
1781  using MapSurfaceExtent = std::unordered_map<struct wl_surface*, Yetani::SurfaceExtent>;
1782 
1783  MapSurfaceExtent surface_extent_map;
1784  std::mutex surface_extent_mutex; // For surface adding and removing
1785 
1786  // -------------------------------------------------- //
1787 
1788  struct SurfaceFrame
1789  {
1790  struct wl_callback* callback;
1791  struct wl_surface* wl_surface;
1792  std::atomic<wl_buffer*> buffer_next;
1793  uint32_t width;
1794  uint32_t height;
1795  uint32_t time_ms;
1796  };
1797 
1798  using MapSurfaceFrame = std::unordered_map<struct wl_surface*, Yetani::SurfaceFrame>;
1799 
1800  MapSurfaceFrame surface_frame_map;
1801 
1802  // -------------------------------------------------- //
1803 
1804  struct SurfaceSize
1805  {
1806  int32_t width;
1807  int32_t height;
1808  int32_t stride;
1809  uint32_t in_bytes;
1810  wl_shm_format pixel_format;
1811  uint8_t bytes_per_pixel;
1812  };
1813 
1814  using MapSurfaceSize = std::unordered_map<struct wl_surface*, Yetani::SurfaceSize>;
1815 
1816  MapSurfaceSize surface_size_map;
1817 
1818  // -------------------------------------------------- //
1819 
1820  using MapSurfaceResizeMutex = std::unordered_map<struct wl_surface*, std::mutex>;
1821 
1822  MapSurfaceResizeMutex surface_resize_mutex_map;
1823 
1824  // -------------------------------------------------- //
1825 
1826  static void surfaceCalculateSize(Yetani*, struct wl_surface*, const Yetani::SizePixel&) noexcept;
1827  static struct wl_surface* surfaceCreate(Yetani*, const wl_shm_format, const Yetani::SizePixel&, const bool, Yetani::Window::Memory&) noexcept;
1828  static void surfaceDestroy(Yetani*, struct wl_surface*&) noexcept;
1829 
1830  // }}}
1831  // {{{ Window
1832 
1833  struct WindowData
1834  {
1835  Yetani* yetani;
1836  struct wl_shm* wl_shm;
1837  struct wl_output* wl_output;
1838  std::string file_name;
1839  Yetani::SizeMm size_mm;
1840  Yetani::SizePercent size_percent;
1841  Yetani::SizePixel size_pixel;
1842  Yetani::SizeUnit size_unit;
1843  wl_shm_format pixel_format;
1844  std::error_code error;
1845  };
1846 
1847  // -------------------------------------------------- //
1848 
1849  Yetani::Window* windowCreate(const Yetani::SizeUnit, const Yetani::SizeMm&, const Yetani::SizePercent&, const Yetani::SizePixel&, const wl_shm_format, std::error_code&) noexcept;
1850  void windowDataInit(Yetani::WindowData&) noexcept;
1851  void windowDataInitOutput(Yetani::WindowData&) noexcept;
1852  void windowInitMemory(Yetani::WindowData&, Yetani::Window::Memory&) noexcept;
1853  void windowInitOutput(Yetani::WindowData&, struct wl_surface*) noexcept;
1854  void windowEraseMemory(Yetani::Window::Memory&) noexcept;
1855  void windowEraseOutput(struct wl_surface*) noexcept;
1856  void windowEraseSurfaceExtent(struct wl_surface*) noexcept;
1857 
1858  // }}}
1859  // {{{ Utility
1860 
1861  std::vector<Yetani::Window*> window_vector;
1862  std::mutex window_vector_mutex;
1863 
1864  // -------------------------------------------------- //
1865 
1866  void windowAdd(Yetani::Window*) noexcept;
1867  void windowRemove(Yetani::Window*) noexcept;
1868 
1869  // }}}
1870  // {{{ XDG
1871 
1872  enum XdgState : int32_t
1873  { Unknown = 0
1874  , Toplevel_Active = 1
1875  , Toplevel_Attach_Buffer = 2
1876  , Toplevel_Resizing = 3
1877  , Toplevel_Window_Fullscreen = 4
1878  , Toplevel_Window_Maximized = 5
1879  , Toplevel_Window_Normal = 6
1880  , Toplevel_Decoration = 7
1881  };
1882 
1883  using VectorXdgStateChange = std::vector<int32_t>;
1884  using MapXdgStateChange = std::unordered_map<struct xdg_surface*, Yetani::VectorXdgStateChange>;
1885 
1886  Yetani::MapXdgStateChange xdg_state_change_map;
1887  std::mutex xdg_state_change_mutex;
1888 
1889  // -------------------------------------------------- //
1890 
1891  struct xdg_wm_base* xdg_wm_base;
1892 
1893  // -------------------------------------------------- //
1894 
1895  static Yetani::WindowMode toWindowMode(const Yetani::XdgState) noexcept;
1896  static Yetani::XdgState toXdgState(const Yetani::WindowMode) noexcept;
1897 
1898  // }}}
1899  // {{{ XDG : Surface
1900 
1901  struct XdgSurface
1902  {
1903  Yetani* yetani = nullptr;
1904  struct wl_surface* wl_surface = nullptr;
1905  };
1906 
1907  using MapXdgSurface = std::unordered_map<struct wl_surface*, Yetani::XdgSurface>;
1908 
1909  Yetani::MapXdgSurface xdg_surface_map;
1910 
1911  // -------------------------------------------------- //
1912 
1913  struct xdg_surface* xdgSurfaceCreate(struct wl_surface*) noexcept;
1914  void xdgSurfaceDestroy(struct wl_surface*, struct xdg_surface*&) noexcept;
1915  void xdgSurfaceSetExtent(struct wl_surface*, const Yetani::SizeUnit&, const Yetani::SizeMm&, const Yetani::SizePercent&, const Yetani::SizePixel&) noexcept;
1916 
1917  // }}}
1918  // {{{ XDG : Toplevel
1919 
1920  struct XdgToplevel
1921  {
1922  Yetani::VectorXdgStateChange* state_change;
1923  Yetani::Lambda close_request_lambda;
1924  Yetani::LambdaBool is_active_lambda;
1925  bool is_active;
1926  Yetani::XdgState window_state;
1927  Yetani::LambdaWindowMode window_state_lambda;
1928  Yetani::SizePixel previous_size;
1929  struct xdg_toplevel* xdg_toplevel;
1930  };
1931 
1932  using MapXdgToplevel = std::unordered_map<struct xdg_surface*, Yetani::XdgToplevel>;
1933 
1934  MapXdgToplevel xdg_toplevel_map;
1935 
1936  // -------------------------------------------------- //
1937 
1938  struct xdg_toplevel* xdgToplevelCreate(struct xdg_surface*) noexcept;
1939  void xdgToplevelDestroy(struct xdg_surface*, struct xdg_toplevel*&) noexcept;
1940  static void xdgToplevelSizeChange(Yetani*, struct wl_surface*, const Yetani::SizePixel&) noexcept;
1941  static void xdgToplevelSizeMinMaxChange(Yetani*, struct xdg_toplevel*, struct wl_surface*, const Yetani::SizePixel&, const Yetani::SizePixel&) noexcept;
1942  static void xdgToplevelWindowChange(Yetani*, struct wl_surface*, Yetani::XdgToplevel&, const Yetani::XdgState, const Yetani::SizePixel&) noexcept;
1943 
1944  // }}}
1945  // {{{ XDG : Decoration Manager (Unstable)
1946 
1947  struct XdgDecoration
1948  {
1949  Yetani::VectorXdgStateChange* state_change;
1951  uint32_t state;
1952  bool is_present;
1953  //struct zxdg_toplevel_decoration_v1* xdg_decoration;
1954  };
1955 
1956  using MapXdgDecoration = std::unordered_map<struct xdg_surface*, Yetani::XdgDecoration>;
1957 
1958  MapXdgDecoration xdg_decoration_map;
1959 
1960  // -------------------------------------------------- //
1961 
1962  struct zxdg_decoration_manager_v1* decoration_manager;
1963 
1964  // -------------------------------------------------- //
1965 
1966  struct zxdg_toplevel_decoration_v1* xdgDecorationCreate(struct xdg_surface*, struct xdg_toplevel*) noexcept;
1967  void xdgDecorationDestroy(struct xdg_surface*, struct xdg_toplevel*, struct zxdg_toplevel_decoration_v1*&) noexcept;
1968  static void xdgDecorationChange(Yetani::XdgDecoration&, const uint32_t) noexcept;
1969 
1970  // }}}
1971  // {{{ Listener Handlers : Wayland
1972 
1973  static struct wl_buffer_listener buffer_listener;
1974  static struct wl_callback_listener frame_callback_listener;
1975  static struct wl_keyboard_listener keyboard_listener;
1976  static struct wl_output_listener output_listener;
1977  static struct wl_pointer_listener pointer_listener;
1978  static struct wl_registry_listener registry_listener;
1979  static struct wl_seat_listener seat_listener;
1980  static struct wl_shm_listener shm_listener;
1981  static struct wl_surface_listener surface_listener;
1982 
1983  // -------------------------------------------------- //
1984 
1985  static void handlerBufferRelease(void*, struct wl_buffer*) noexcept;
1986 
1987  static void handlerKeyboardEnter(void*, struct wl_keyboard*, uint32_t, struct wl_surface*, struct wl_array*) noexcept;
1988  static void handlerKeyboardKey(void*, struct wl_keyboard*, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
1989  static void handlerKeyboardKeymap(void*, struct wl_keyboard*, uint32_t, int32_t, uint32_t) noexcept;
1990  static void handlerKeyboardLeave(void*, struct wl_keyboard*, uint32_t, struct wl_surface*) noexcept;
1991  static void handlerKeyboardModifiers(void*, struct wl_keyboard*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
1992  static void handlerKeyboardRepeatInfo(void*, struct wl_keyboard*, int32_t, int32_t) noexcept;
1993 
1994  static void handlerOutputDone(void*, struct wl_output*) noexcept;
1995  static void handlerOutputGeometry(void*, struct wl_output*, int32_t, int32_t, int32_t, int32_t, int32_t, const char*, const char*, int32_t) noexcept;
1996  static void handlerOutputMode(void*, struct wl_output*, uint32_t, int32_t, int32_t, int32_t) noexcept;
1997  static void handlerOutputScale(void*, struct wl_output*, int32_t) noexcept;
1998  static void handlerPointerAxis(void*, struct wl_pointer*, uint32_t, uint32_t, wl_fixed_t) noexcept;
1999  static void handlerPointerAxisDiscrete(void*, struct wl_pointer*, uint32_t, int32_t) noexcept;
2000  static void handlerPointerAxisSource(void*, struct wl_pointer*, uint32_t) noexcept;
2001  static void handlerPointerAxisStop(void*, struct wl_pointer*, uint32_t, uint32_t) noexcept;
2002  static void handlerPointerButton(void*, struct wl_pointer*, uint32_t, uint32_t, uint32_t, uint32_t) noexcept;
2003  static void handlerPointerEnter(void*, struct wl_pointer*, uint32_t, struct wl_surface*, wl_fixed_t, wl_fixed_t) noexcept;
2004  static void handlerPointerFrame(void*, struct wl_pointer*) noexcept;
2005  static void handlerPointerLeave(void*, struct wl_pointer*, uint32_t, struct wl_surface*) noexcept;
2006  static void handlerPointerMotion(void*, struct wl_pointer*, uint32_t, wl_fixed_t, wl_fixed_t) noexcept;
2007  static void handlerRegistryGlobal(void*, struct wl_registry*, uint32_t, const char*, uint32_t) noexcept;
2008  static void handlerRegistryRemove(void*, struct wl_registry*, uint32_t) noexcept;
2009  static void handlerSeatCapabilities(void*, struct wl_seat*, uint32_t) noexcept;
2010  static void handlerSeatName(void*, struct wl_seat*, const char*) noexcept;
2011  static void handlerShmFormat(void*, struct wl_shm*, uint32_t) noexcept;
2012  static void handlerSurfaceEnter(void*, struct wl_surface*, struct wl_output*) noexcept;
2013  static void handlerSurfaceLeave(void*, struct wl_surface*, struct wl_output*) noexcept;
2014  static void handlerSwapBuffers(void*, struct wl_callback*, uint32_t) noexcept;
2015 
2016  // }}}
2017  // {{{ Listener Handlers : Wayland Unstable
2018  // }}}
2019  // {{{ Listener Handlers : XDG
2020 
2021  static struct xdg_wm_base_listener xdg_wm_base_listener;
2022  static struct xdg_surface_listener xdg_surface_listener;
2023  static struct xdg_toplevel_listener xdg_toplevel_listener;
2024 
2025  // -------------------------------------------------- //
2026 
2027  static void handlerXdgSurfaceConfigure(void*, struct xdg_surface*, uint32_t) noexcept;
2028  static void handlerXdgToplevelClose(void*, struct xdg_toplevel*) noexcept;
2029  static void handlerXdgToplevelConfigure(void*, struct xdg_toplevel*, int32_t, int32_t, struct wl_array*) noexcept;
2030  static void handlerXdgWmBasePing(void*, struct xdg_wm_base*, uint32_t) noexcept;
2031 
2032  // }}}
2033  // {{{ Listener Handlers : XDG Unstable
2034 
2035  static struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener;
2036 
2037  // -------------------------------------------------- //
2038 
2039  static void handlerXdgToplevelDecorationConfigure(void*, struct zxdg_toplevel_decoration_v1*, uint32_t mode) noexcept;
2040 
2041  // }}}
2042  }; // class Yetani
2043 
2044  // }}}
2045  // {{{ Convenience
2046 
2047  std::string to_string(const wl_shm_format) noexcept;
2048  std::string to_string(const std::error_code&) noexcept;
2049  std::string to_string(const Yetani::KeyModifier&) noexcept;
2050  std::string to_string(const Yetani::KeyState) noexcept;
2051  std::string to_string(const Yetani::Output&) noexcept;
2052  std::string to_string(const Yetani::PointerAxisSource) noexcept;
2053  std::string to_string(const Yetani::PointerAxisType) noexcept;
2054  std::string to_string(const Yetani::PointerButtonState) noexcept;
2055  std::string to_string(const Yetani::WindowMode) noexcept;
2056 
2057  // }}}
2058 }
2059 
2060 // {{{ Implementation
2061 
2062 #ifdef ZAKERO_YETANI_IMPLEMENTATION
2063 
2064 // {{{ Macros
2065 
2066 // {{{ Macros : Doxygen
2067 
2068 #ifdef ZAKERO__DOXYGEN_DEFINE_DOCS
2069 
2070 // Only used for generating Doxygen documentation
2071 
2083 #define ZAKERO_YETANI_IMPLEMENTATION
2093 #define ZAKERO_YETANI_ENABLE_DEBUG
2103 #define ZAKERO_YETANI_ENABLE_SAFE_MODE
2105 #endif // ZAKERO__DOXYGEN_DEFINE_DOCS
2106 
2107 // }}}
2108 
2124 #ifdef ZAKERO_YETANI_ENABLE_DEBUG
2125 #define ZAKERO_YETANI__DEBUG_DISABLED false
2126 #else
2127 #define ZAKERO_YETANI__DEBUG_DISABLED true
2128 #endif
2129 
2130 
2143 #ifndef ZAKERO_YETANI_ENABLE_DEBUG_STREAM
2144 #define ZAKERO_YETANI_ENABLE_DEBUG_STREAM std::cerr
2145 #endif
2146 
2147 
2165 #define ZAKERO_YETANI__DEBUG \
2166  if(ZAKERO_YETANI__DEBUG_DISABLED) {} \
2167  else ZAKERO_YETANI_ENABLE_DEBUG_STREAM \
2168  << __FILE__"(" \
2169  << std::to_string(__LINE__) \
2170  << ") " \
2171  << __PRETTY_FUNCTION__ \
2172  << " "
2173 
2190 #define ZAKERO_YETANI__DEBUG_VAR(var_) \
2191  ZAKERO_YETANI__DEBUG \
2192  << #var_ << ": " << var_ \
2193  << "\n";
2194 
2210 #define ZAKERO_YETANI__DEBUG_BOOL(var_) \
2211  ZAKERO_YETANI__DEBUG \
2212  << #var_ << ": " << std::boolalpha << var_ \
2213  << "\n";
2214 
2225 #define ZAKERO_YETANI__ERROR(err_) std::error_code(err_, YetaniErrorCategory)
2226 
2227 
2244 #define ZAKERO_YETANI__SHM_FORMAT \
2245  X(WL_SHM_FORMAT_ARGB8888 , 4 , "32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian" ) \
2246  X(WL_SHM_FORMAT_XRGB8888 , 4 , "32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian" ) \
2247  X(WL_SHM_FORMAT_C8 , 1 , "8-bit color index format, [7:0] C" ) \
2248  X(WL_SHM_FORMAT_RGB332 , 1 , "8-bit RGB format, [7:0] R:G:B 3:3:2" ) \
2249  X(WL_SHM_FORMAT_BGR233 , 1 , "8-bit BGR format, [7:0] B:G:R 2:3:3" ) \
2250  X(WL_SHM_FORMAT_XRGB4444 , 2 , "16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian" ) \
2251  X(WL_SHM_FORMAT_XBGR4444 , 2 , "16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian" ) \
2252  X(WL_SHM_FORMAT_RGBX4444 , 2 , "16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian" ) \
2253  X(WL_SHM_FORMAT_BGRX4444 , 2 , "16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian" ) \
2254  X(WL_SHM_FORMAT_ARGB4444 , 2 , "16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian" ) \
2255  X(WL_SHM_FORMAT_ABGR4444 , 2 , "16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian" ) \
2256  X(WL_SHM_FORMAT_RGBA4444 , 2 , "16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian" ) \
2257  X(WL_SHM_FORMAT_BGRA4444 , 2 , "16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian" ) \
2258  X(WL_SHM_FORMAT_XRGB1555 , 2 , "16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian" ) \
2259  X(WL_SHM_FORMAT_XBGR1555 , 2 , "16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian" ) \
2260  X(WL_SHM_FORMAT_RGBX5551 , 2 , "16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian" ) \
2261  X(WL_SHM_FORMAT_BGRX5551 , 2 , "16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian" ) \
2262  X(WL_SHM_FORMAT_ARGB1555 , 2 , "16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian" ) \
2263  X(WL_SHM_FORMAT_ABGR1555 , 2 , "16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian" ) \
2264  X(WL_SHM_FORMAT_RGBA5551 , 2 , "16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian" ) \
2265  X(WL_SHM_FORMAT_BGRA5551 , 2 , "16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian" ) \
2266  X(WL_SHM_FORMAT_RGB565 , 2 , "16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian" ) \
2267  X(WL_SHM_FORMAT_BGR565 , 2 , "16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian" ) \
2268  X(WL_SHM_FORMAT_RGB888 , 3 , "24-bit RGB format, [23:0] R:G:B little endian" ) \
2269  X(WL_SHM_FORMAT_BGR888 , 3 , "24-bit BGR format, [23:0] B:G:R little endian" ) \
2270  X(WL_SHM_FORMAT_XBGR8888 , 4 , "32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian" ) \
2271  X(WL_SHM_FORMAT_RGBX8888 , 4 , "32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian" ) \
2272  X(WL_SHM_FORMAT_BGRX8888 , 4 , "32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian" ) \
2273  X(WL_SHM_FORMAT_ABGR8888 , 4 , "32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian" ) \
2274  X(WL_SHM_FORMAT_RGBA8888 , 4 , "32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian" ) \
2275  X(WL_SHM_FORMAT_BGRA8888 , 4 , "32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian" ) \
2276  X(WL_SHM_FORMAT_XRGB2101010 , 4 , "32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian" ) \
2277  X(WL_SHM_FORMAT_XBGR2101010 , 4 , "32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian" ) \
2278  X(WL_SHM_FORMAT_RGBX1010102 , 4 , "32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian" ) \
2279  X(WL_SHM_FORMAT_BGRX1010102 , 4 , "32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian" ) \
2280  X(WL_SHM_FORMAT_ARGB2101010 , 4 , "32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian" ) \
2281  X(WL_SHM_FORMAT_ABGR2101010 , 4 , "32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian" ) \
2282  X(WL_SHM_FORMAT_RGBA1010102 , 4 , "32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian" ) \
2283  X(WL_SHM_FORMAT_BGRA1010102 , 4 , "32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian" ) \
2284  X(WL_SHM_FORMAT_YUYV , 4 , "packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian" ) \
2285  X(WL_SHM_FORMAT_YVYU , 4 , "packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian" ) \
2286  X(WL_SHM_FORMAT_UYVY , 4 , "packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian" ) \
2287  X(WL_SHM_FORMAT_VYUY , 4 , "packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian" ) \
2288  X(WL_SHM_FORMAT_AYUV , 4 , "packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian" ) \
2289  X(WL_SHM_FORMAT_NV12 , 8 , "2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane" ) \
2290  X(WL_SHM_FORMAT_NV21 , 8 , "2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane" ) \
2291  X(WL_SHM_FORMAT_NV16 , 8 , "2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane" ) \
2292  X(WL_SHM_FORMAT_NV61 , 8 , "2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane" ) \
2293  X(WL_SHM_FORMAT_YUV410 , 8 , "3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes" ) \
2294  X(WL_SHM_FORMAT_YVU410 , 8 , "3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes" ) \
2295  X(WL_SHM_FORMAT_YUV411 , 8 , "3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes" ) \
2296  X(WL_SHM_FORMAT_YVU411 , 8 , "3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes" ) \
2297  X(WL_SHM_FORMAT_YUV420 , 8 , "3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes" ) \
2298  X(WL_SHM_FORMAT_YVU420 , 8 , "3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes" ) \
2299  X(WL_SHM_FORMAT_YUV422 , 8 , "3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes" ) \
2300  X(WL_SHM_FORMAT_YVU422 , 8 , "3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes" ) \
2301  X(WL_SHM_FORMAT_YUV444 , 8 , "3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes" ) \
2302  X(WL_SHM_FORMAT_YVU444 , 8 , "3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes" ) \
2303  X(WL_SHM_FORMAT_R8 , 1 , "[7:0] R" ) \
2304  X(WL_SHM_FORMAT_R16 , 2 , "[15:0] R little endian" ) \
2305  X(WL_SHM_FORMAT_RG88 , 2 , "[15:0] R:G 8:8 little endian" ) \
2306  X(WL_SHM_FORMAT_GR88 , 2 , "[15:0] G:R 8:8 little endian" ) \
2307  X(WL_SHM_FORMAT_RG1616 , 4 , "[31:0] R:G 16:16 little endian" ) \
2308  X(WL_SHM_FORMAT_GR1616 , 4 , "[31:0] G:R 16:16 little endian" ) \
2309  X(WL_SHM_FORMAT_XRGB16161616F , 8 , "[63:0] x:R:G:B 16:16:16:16 little endian" ) \
2310  X(WL_SHM_FORMAT_XBGR16161616F , 8 , "[63:0] x:B:G:R 16:16:16:16 little endian" ) \
2311  X(WL_SHM_FORMAT_ARGB16161616F , 8 , "[63:0] A:R:G:B 16:16:16:16 little endian" ) \
2312  X(WL_SHM_FORMAT_ABGR16161616F , 8 , "[63:0] A:B:G:R 16:16:16:16 little endian" ) \
2313  X(WL_SHM_FORMAT_XYUV8888 , 4 , "[31:0] X:Y:Cb:Cr 8:8:8:8 little endian" ) \
2314  X(WL_SHM_FORMAT_VUY888 , 3 , "[23:0] Cr:Cb:Y 8:8:8 little endian" ) \
2315  X(WL_SHM_FORMAT_VUY101010 , 4 , "Y followed by U then V, 10:10:10. Non-linear modifier only" ) \
2316  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" ) \
2317  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" ) \
2318  X(WL_SHM_FORMAT_Y216 , 8 , "[63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels" ) \
2319  X(WL_SHM_FORMAT_Y410 , 4 , "[31:0] A:Cr:Y:Cb 2:10:10:10 little endian" ) \
2320  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" ) \
2321  X(WL_SHM_FORMAT_Y416 , 8 , "[63:0] A:Cr:Y:Cb 16:16:16:16 little endian" ) \
2322  X(WL_SHM_FORMAT_XVYU2101010 , 4 , "[31:0] X:Cr:Y:Cb 2:10:10:10 little endian" ) \
2323  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" ) \
2324  X(WL_SHM_FORMAT_XVYU16161616 , 8 , "[63:0] X:Cr:Y:Cb 16:16:16:16 little endian" ) \
2325  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" ) \
2326  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" ) \
2327  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" ) \
2328  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" ) \
2329  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" ) \
2330  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" ) \
2331  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" ) \
2332  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" ) \
2333  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" ) \
2334  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" ) \
2335  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" ) \
2336  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" ) \
2337  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" ) \
2338  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" ) \
2339  X(WL_SHM_FORMAT_NV24 , 0 , "[UNKNOWN SIZE] non-subsampled Cr:Cb plane" ) \
2340  X(WL_SHM_FORMAT_NV42 , 0 , "[UNKNOWN SIZE] non-subsampled Cb:Cr plane" ) \
2341  X(WL_SHM_FORMAT_P210 , 0 , "[UNKNOWN SIZE] 2x1 subsampled Cr:Cb plane, 10 bits per channel" ) \
2342  X(WL_SHM_FORMAT_P010 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 10 bits per channel" ) \
2343  X(WL_SHM_FORMAT_P012 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 12 bits per channel" ) \
2344  X(WL_SHM_FORMAT_P016 , 0 , "[UNKNOWN SIZE] 2x2 subsampled Cr:Cb plane, 16 bits per channel" ) \
2345 
2346 
2352 #define ZAKERO_YETANI__OUTPUT_SUBPIXEL \
2353  X(WL_OUTPUT_SUBPIXEL_UNKNOWN , "Unkown Geometry" ) \
2354  X(WL_OUTPUT_SUBPIXEL_NONE , "No Geometry" ) \
2355  X(WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB , "Horizontal RGB" ) \
2356  X(WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR , "Horizontal BGR" ) \
2357  X(WL_OUTPUT_SUBPIXEL_VERTICAL_RGB , "Vertical RGB" ) \
2358  X(WL_OUTPUT_SUBPIXEL_VERTICAL_BGR , "Vertical BGR" ) \
2359 
2360 
2366 #define ZAKERO_YETANI__OUTPUT_TRANSFORM \
2367  X(WL_OUTPUT_TRANSFORM_NORMAL , "No Transform" ) \
2368  X(WL_OUTPUT_TRANSFORM_90 , "90 degrees Counter-Clockwise" ) \
2369  X(WL_OUTPUT_TRANSFORM_180 , "180 degrees Counter-Clockwise" ) \
2370  X(WL_OUTPUT_TRANSFORM_270 , "270 degrees Counter-Clockwise" ) \
2371  X(WL_OUTPUT_TRANSFORM_FLIPPED , "180 degree flip around a vertical axis" ) \
2372  X(WL_OUTPUT_TRANSFORM_FLIPPED_90 , "Flig and rotate 90 degrees counter-clockwise" ) \
2373  X(WL_OUTPUT_TRANSFORM_FLIPPED_180 , "Flig and rotate 180 degrees counter-clockwise" ) \
2374 
2375 
2399 #define ZAKERO_YETANI__ARRAY_FOR_EACH(type_, pos_, array_) \
2400  for(type_ pos_ = (type_)(array_)->data \
2401  ; (const char*)pos_ < ((const char*)(array_)->data + (array_)->size) \
2402  ; (pos_)++ \
2403  )
2404 
2405 // }}}
2406 
2407 namespace zakero
2408 {
2409 // {{{ Anonymous Namespace
2410 
2411 namespace
2412 {
2413  // {{{ Cursor Names (Not used yet)
2414  /*
2415  * \brief Common cursor names
2416  *
2417  * These were found in:
2418  * - gdkcursor-wayland.c
2419  * - /usr/share/icons/whiteglass/cursors
2420  const std::array<const char*, 131> common_cursor_names =
2421  { "X_cursor"
2422  , "alias"
2423  , "all-scroll"
2424  , "arrow"
2425  , "base_arrow_down"
2426  , "base_arrow_up"
2427  , "bd_double_arrow"
2428  , "boat"
2429  , "bottom_left_corner"
2430  , "bottom_right_corner"
2431  , "bottom_side"
2432  , "bottom_tee"
2433  , "cell"
2434  , "center_ptr"
2435  , "circle"
2436  , "closedhand"
2437  , "col-resize"
2438  , "color-picker"
2439  , "context-menu"
2440  , "copy"
2441  , "cross"
2442  , "cross_reverse"
2443  , "crossed_circle"
2444  , "crosshair"
2445  , "default"
2446  , "dnd-copy"
2447  , "dnd-link"
2448  , "dnd-move"
2449  , "dnd-no-drop"
2450  , "dnd-none"
2451  , "dot"
2452  , "dot_box_mask"
2453  , "double_arrow"
2454  , "down-arrow"
2455  , "draft"
2456  , "draft_large"
2457  , "draft_small"
2458  , "draped_box"
2459  , "e-resize"
2460  , "ew-resize"
2461  , "exchange"
2462  , "fd_double_arrow"
2463  , "fleur"
2464  , "forbidden"
2465  , "grab"
2466  , "grabbing"
2467  , "gumby"
2468  , "h_double_arrow"
2469  , "half-busy"
2470  , "hand"
2471  , "hand1"
2472  , "hand2"
2473  , "help"
2474  , "ibeam"
2475  , "left-arrow"
2476  , "left_ptr"
2477  , "left_ptr_help"
2478  , "left_ptr_watch"
2479  , "left_side"
2480  , "left_tee"
2481  , "link"
2482  , "ll_angle"
2483  , "lr_angle"
2484  , "move"
2485  , "n-resize"
2486  , "ne-resize"
2487  , "nesw-resize"
2488  , "no-drop"
2489  , "not-allowed"
2490  , "ns-resize"
2491  , "nw-resize"
2492  , "nwse-resize"
2493  , "openhand"
2494  , "pencil"
2495  , "pirate"
2496  , "plus"
2497  , "pointer"
2498  , "pointing_hand"
2499  , "progress"
2500  , "question_arrow"
2501  , "right-arrow"
2502  , "right_ptr"
2503  , "right_side"
2504  , "right_tee"
2505  , "row-resize"
2506  , "s-resize"
2507  , "sailboat"
2508  , "sb_down_arrow"
2509  , "sb_h_double_arrow"
2510  , "sb_left_arrow"
2511  , "sb_right_arrow"
2512  , "sb_up_arrow"
2513  , "sb_v_double_arrow"
2514  , "se-resize"
2515  , "shuttle"
2516  , "size-bdiag"
2517  , "size-fdiag"
2518  , "size-hor"
2519  , "size-ver"
2520  , "size_all"
2521  , "size_bdiag"
2522  , "size_fdiag"
2523  , "size_hor"
2524  , "size_ver"
2525  , "sizing"
2526  , "split_h"
2527  , "split_v"
2528  , "sw-resize"
2529  , "target"
2530  , "tcross"
2531  , "text"
2532  , "top_left_arrow"
2533  , "top_left_corner"
2534  , "top_right_corner"
2535  , "top_side"
2536  , "top_tee"
2537  , "trek"
2538  , "ul_angle"
2539  , "up-arrow"
2540  , "ur_angle"
2541  , "v_double_arrow"
2542  , "vertical-text"
2543  , "w-resize"
2544  , "wait"
2545  , "watch"
2546  , "wayland-cursor"
2547  , "whats_this"
2548  , "x-cursor"
2549  , "xterm"
2550  , "zoom-in"
2551  , "zoom-out"
2552  };
2553  */
2554  // }}}
2555 
2565  class YetaniErrorCategory_
2566  : public std::error_category
2567  {
2568  public:
2569  constexpr YetaniErrorCategory_() noexcept
2570  {
2571  }
2572 
2573  const char* name() const noexcept override
2574  {
2575  return "zakero.Yetani";
2576  }
2577 
2578  std::string message(int condition) const override
2579  {
2580  switch(condition)
2581  {
2582 #define X(name_, val_, mesg_) \
2583  case val_: return mesg_;
2584  ZAKERO_YETANI__ERROR_DATA
2585 #undef X
2586  }
2587 
2588  return "Unknown error condition";
2589  }
2590  } YetaniErrorCategory;
2591 
2592 
2597  Yetani::Lambda Lambda_DoNothing = [](){};
2598  Yetani::LambdaKey LambdaKey_DoNothing = [](const Yetani::Key&, const Yetani::KeyModifier&){};
2599  Yetani::LambdaAxis LambdaAxis_DoNothing = [](const Yetani::PointerAxis&, const Yetani::KeyModifier&){};
2600  Yetani::LambdaButtonMm LambdaButtonMm_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointMm&, const Yetani::KeyModifier&){};
2601  Yetani::LambdaButtonPercent LambdaButtonPercent_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointPercent&, const Yetani::KeyModifier&){};
2602  Yetani::LambdaButtonPixel LambdaButtonPixel_DoNothing = [](const Yetani::PointerButton&, const Yetani::PointPixel&, const Yetani::KeyModifier&){};
2603  Yetani::LambdaPointMm LambdaPointMm_DoNothing = [](const Yetani::PointMm&, const Yetani::KeyModifier&){};
2604  Yetani::LambdaPointPercent LambdaPointPercent_DoNothing = [](const Yetani::PointPercent&, const Yetani::KeyModifier&){};
2605  Yetani::LambdaPointPixel LambdaPointPixel_DoNothing = [](const Yetani::PointPixel&, const Yetani::KeyModifier&){};
2606  Yetani::LambdaBool LambdaBool_DoNothing = [](const bool){};
2607  Yetani::LambdaOutputId LambdaOutputId_DoNothing = [](const Yetani::OutputId){};
2608  Yetani::LambdaWindowDecorations LambdaWindowDecorations_DoNothing = [](const Yetani::WindowDecorations){};
2609  Yetani::LambdaWindowMode LambdaWindowMode_DoNothing = [](const Yetani::WindowMode){};
2610  Yetani::LambdaSizeMm LambdaSizeMm_DoNothing = [](const Yetani::SizeMm&){};
2611  Yetani::LambdaSizePercent LambdaSizePercent_DoNothing = [](const Yetani::SizePercent&){};
2612  Yetani::LambdaSizePixel LambdaSizePixel_DoNothing = [](const Yetani::SizePixel&){};
2629  bool equalish(const float a
2630  , const float b
2631  , const float delta
2632  ) noexcept
2633  {
2634  return (std::abs(a - b) < delta);
2635  }
2636 
2637 
2650  inline size_t sizeInBytes(const Yetani::SizePixel& size
2651  , const wl_shm_format format
2652  ) noexcept
2653  {
2654  return size.width
2655  * size.height
2657  ;
2658  };
2659 
2660 
2674  template<class Type
2675  >
2676  std::error_code validateMinMax(const Type& min
2677  , const Type& max
2678  ) noexcept
2679  {
2680  if((min.width < 0)
2681  || (min.height < 0)
2682  || (max.width < 0)
2683  || (max.height < 0)
2684  )
2685  {
2686  return ZAKERO_YETANI__ERROR(Yetani::Error_Window_Size_Too_Small);
2687  }
2688 
2689  if((min.width > 0)
2690  && (max.width > 0)
2691  && (min.width > max.width)
2692  )
2693  {
2694  return ZAKERO_YETANI__ERROR(Yetani::Error_Minimum_Size_Greater_Than_Maximum_Size);
2695  }
2696 
2697  if((min.height > 0)
2698  && (max.height > 0)
2699  && (min.height > max.height)
2700  )
2701  {
2702  return ZAKERO_YETANI__ERROR(Yetani::Error_Minimum_Size_Greater_Than_Maximum_Size);
2703  }
2704 
2705  return ZAKERO_YETANI__ERROR(Yetani::Error_None);
2706  };
2707 }
2708 
2709 // }}}
2710 // {{{ Documentation
2711 
2836 /* Disabled because Doxygen does not support "enum classes"
2837  *
2838  * \var Yetani::Released
2839  * \brief The key was released
2840  *
2841  * \var Yetani::Pressed
2842  * \brief The key was pressed
2843  *
2844  * \var Yetani::Repeat
2845  * \brief The key is being held down
2846  */
2847 
3077 // }}}
3078 // {{{ Static Member Initialization
3079 // {{{ Listener Handler : Wayland
3080 
3081 struct wl_buffer_listener Yetani::buffer_listener =
3082 { .release = &Yetani::handlerBufferRelease
3083 };
3084 
3085 struct wl_callback_listener Yetani::frame_callback_listener =
3086 { .done = &Yetani::handlerSwapBuffers
3087 };
3088 
3089 struct wl_keyboard_listener Yetani::keyboard_listener =
3090 { .keymap = &Yetani::handlerKeyboardKeymap
3091 , .enter = &Yetani::handlerKeyboardEnter
3092 , .leave = &Yetani::handlerKeyboardLeave
3093 , .key = &Yetani::handlerKeyboardKey
3094 , .modifiers = &Yetani::handlerKeyboardModifiers
3095 , .repeat_info = &Yetani::handlerKeyboardRepeatInfo
3096 };
3097 
3098 struct wl_output_listener Yetani::output_listener =
3099 { .geometry = &Yetani::handlerOutputGeometry
3100 , .mode = &Yetani::handlerOutputMode
3101 , .done = &Yetani::handlerOutputDone
3102 , .scale = &Yetani::handlerOutputScale
3103 };
3104 
3105 struct wl_pointer_listener Yetani::pointer_listener =
3106 { .enter = &Yetani::handlerPointerEnter
3107 , .leave = &Yetani::handlerPointerLeave
3108 , .motion = &Yetani::handlerPointerMotion
3109 , .button = &Yetani::handlerPointerButton
3110 , .axis = &Yetani::handlerPointerAxis
3111 , .frame = &Yetani::handlerPointerFrame
3112 , .axis_source = &Yetani::handlerPointerAxisSource
3113 , .axis_stop = &Yetani::handlerPointerAxisStop
3114 , .axis_discrete = &Yetani::handlerPointerAxisDiscrete
3115 };
3116 
3117 struct wl_registry_listener Yetani::registry_listener =
3118 { .global = &Yetani::handlerRegistryGlobal
3119 , .global_remove = &Yetani::handlerRegistryRemove
3120 };
3121 
3122 struct wl_seat_listener Yetani::seat_listener =
3123 { .capabilities = &Yetani::handlerSeatCapabilities
3124 , .name = &Yetani::handlerSeatName
3125 };
3126 
3127 struct wl_shm_listener Yetani::shm_listener =
3128 { .format = &Yetani::handlerShmFormat
3129 };
3130 
3131 struct wl_surface_listener Yetani::surface_listener =
3132 { .enter = &Yetani::handlerSurfaceEnter
3133 , .leave = &Yetani::handlerSurfaceLeave
3134 };
3135 
3136 // }}}
3137 // {{{ Listener Handler : Wayland Unstable
3138 // }}}
3139 // {{{ Listener Handler : XDG
3140 
3141 struct xdg_wm_base_listener Yetani::xdg_wm_base_listener =
3142 { .ping = &Yetani::handlerXdgWmBasePing
3143 };
3144 
3145 struct xdg_surface_listener Yetani::xdg_surface_listener =
3146 { .configure = &Yetani::handlerXdgSurfaceConfigure
3147 };
3148 
3149 struct xdg_toplevel_listener Yetani::xdg_toplevel_listener =
3150 { .configure = &Yetani::handlerXdgToplevelConfigure
3151 , .close = &Yetani::handlerXdgToplevelClose
3152 };
3153 
3154 // }}}
3155 // {{{ Listener Handler : XDG Unstable
3156 
3157 struct zxdg_toplevel_decoration_v1_listener Yetani::xdg_toplevel_decoration_listener =
3158 { .configure = &Yetani::handlerXdgToplevelDecorationConfigure
3159 };
3160 
3161 // }}}
3162 // }}}
3163 // {{{ Constructor / Destructor
3164 
3170 Yetani::Yetani() noexcept
3171  : cursor_map()
3172  , cursor_surface_map()
3173  , cursor_memory_pool(
3174  std::string("Zakero.Yetani.")
3175  + std::to_string(ZAKERO_STEADY_TIME_NOW(nanoseconds))
3176  )
3177  , cursor_mutex()
3178  , cursor_shm_pool(nullptr)
3179  , cursor_pointer(nullptr)
3180  , event_loop()
3181  , event_loop_is_running(false)
3182  , compositor(nullptr)
3183  , display(nullptr)
3184  , registry(nullptr)
3185  , shm(nullptr)
3186  , shm_format_vector()
3187  , seat_map()
3188  , id_to_seat()
3189  , seat(nullptr)
3190  , keyboard()
3191  , pointer()
3192  , output_data()
3193  , on_output_add(LambdaOutputId_DoNothing)
3194  , on_output_change(LambdaOutputId_DoNothing)
3195  , on_output_remove(LambdaOutputId_DoNothing)
3196  , output_changes_map()
3197  , output_state_map()
3198  , output_notify_surface_vector()
3199  , buffer()
3200  , surface_event_map()
3201  , surface_extent_map()
3202  , surface_extent_mutex()
3203  , surface_frame_map()
3204  , surface_size_map()
3205  , surface_resize_mutex_map()
3206  , window_vector()
3207  , window_vector_mutex()
3208  , xdg_state_change_map()
3209  , xdg_state_change_mutex()
3210  , xdg_wm_base(nullptr)
3211  , xdg_surface_map()
3212  , xdg_toplevel_map()
3213  , xdg_decoration_map()
3214  , decoration_manager(nullptr)
3215 {
3216 }
3217 
3218 
3229 {
3230  if(event_loop_is_running || event_loop.joinable())
3231  {
3232  event_loop.request_stop();
3233  event_loop.join();
3234  }
3235 
3236  disconnect();
3237 }
3238 
3239 // }}}
3240 // {{{ Connection
3241 
3265 {
3266  std::error_code error;
3267 
3268  return Yetani::connect("", error);
3269 }
3270 
3271 
3296 Yetani* Yetani::connect(const std::string& display
3297  ) noexcept
3298 {
3299  std::error_code error;
3300 
3301  return Yetani::connect(display, error);
3302 }
3303 
3304 
3332 Yetani* Yetani::connect(std::error_code& error
3333  ) noexcept
3334 {
3335  return Yetani::connect("", error);
3336 }
3337 
3367 Yetani* Yetani::connect(const std::string& display
3368  , std::error_code& error
3369  ) noexcept
3370 {
3371  Yetani* yetani = new Yetani();
3372 
3373  const char* display_name = nullptr;
3374 
3375  if(display.empty() == false)
3376  {
3377  display_name = display.c_str();
3378  }
3379 
3380  // --- Get the Display --- //
3381  yetani->display = wl_display_connect(display_name);
3382  if(yetani->display == nullptr)
3383  {
3384  delete yetani;
3385 
3386  const char* session = getenv("XDG_SESSION_TYPE");
3387 
3388  if(session != nullptr
3389  && strcasecmp(session, "wayland") != 0
3390  )
3391  {
3392  error = ZAKERO_YETANI__ERROR(Error_Wayland_Not_Available);
3393  }
3394  else if(display.empty())
3395  {
3396  error = ZAKERO_YETANI__ERROR(Error_Connection_Failed);
3397  }
3398  else
3399  {
3400  error = ZAKERO_YETANI__ERROR(Error_Invalid_Display_Name);
3401  }
3402 
3403  return nullptr;
3404  }
3405 
3406  // --- Get the Registry --- //
3407  yetani->registry = wl_display_get_registry(yetani->display);
3408  if(yetani->registry == nullptr)
3409  {
3410  delete yetani;
3411 
3412  error = ZAKERO_YETANI__ERROR(Error_Registry_Not_Available);
3413 
3414  return nullptr;
3415  }
3416 
3417  wl_registry_add_listener(yetani->registry, &registry_listener, yetani);
3418 
3419  // --- Wait for all Global Objects to be registered --- //
3420  wl_display_dispatch(yetani->display);
3421  wl_display_roundtrip(yetani->display);
3422 
3423  // --- Validate required Global Objects --- //
3424  if(yetani->compositor == nullptr)
3425  {
3426  delete yetani;
3427 
3428  error = ZAKERO_YETANI__ERROR(Error_Compositor_Was_Not_Found);
3429 
3430  return nullptr;
3431  }
3432 
3433  if(yetani->shm == nullptr)
3434  {
3435  delete yetani;
3436 
3437  error = ZAKERO_YETANI__ERROR(Error_Shm_Was_Not_Found);
3438 
3439  return nullptr;
3440  }
3441 
3442  if(yetani->xdg_wm_base == nullptr)
3443  {
3444  delete yetani;
3445 
3446  error = ZAKERO_YETANI__ERROR(Error_Xdg_WM_Base_Was_Not_Found);
3447 
3448  return nullptr;
3449  }
3450 
3451  yetani->cursorSetup();
3452 
3453  yetani->eventLoopStart();
3454 
3455  error = ZAKERO_YETANI__ERROR(Error_None);
3456 
3457  return yetani;
3458 }
3459 
3460 
3470 void Yetani::disconnect() noexcept
3471 {
3472  cursorTeardown();
3473 
3474  if(decoration_manager != nullptr)
3475  {
3476  zxdg_decoration_manager_v1_destroy(decoration_manager);
3477  decoration_manager = nullptr;
3478  }
3479 
3480  if(xdg_wm_base != nullptr)
3481  {
3482  xdg_wm_base_destroy(xdg_wm_base);
3483  xdg_wm_base = nullptr;
3484  }
3485 
3486  if(shm != nullptr)
3487  {
3488  wl_shm_destroy(shm);
3489  shm = nullptr;
3490  }
3491 
3492  // Seat
3493  id_to_seat.clear();
3494 
3495  while(seat_map.empty() == false)
3496  {
3497  auto iter = std::begin(seat_map);
3498 
3499  struct wl_seat* wl_seat = iter->first;
3500 
3501  seatDestroy(wl_seat);
3502  }
3503 
3504  // Wayland Output Devices
3505  {
3506  std::lock_guard<std::mutex> lock(output_data.mutex);
3507 
3508  for(auto& iter : output_data.output_map)
3509  {
3510  struct wl_output* wayland_output = iter.first;
3511 
3512  wl_output_destroy(wayland_output);
3513  }
3514 
3515  output_changes_map.clear();
3516  output_state_map.clear();
3517  output_data.output_map.clear();
3518  output_data.wloutput_to_outputid.clear();
3519  output_data.outputid_to_wloutput.clear();
3520  }
3521 
3522  if(registry != nullptr)
3523  {
3524  wl_registry_destroy(registry);
3525  registry = nullptr;
3526  }
3527 
3528  if(compositor != nullptr)
3529  {
3530  wl_compositor_destroy(compositor);
3531  compositor = nullptr;
3532  }
3533 
3534  if(display != nullptr)
3535  {
3536  wl_display_disconnect(display);
3537  display = nullptr;
3538  }
3539 
3540  return;
3541 }
3542 
3543 // }}}
3544 // {{{ Cursor
3545 
3678 void Yetani::cursorAnimate() noexcept
3679 {
3680  int64_t time_now = ZAKERO_STEADY_TIME_NOW(milliseconds);
3681 
3682  std::lock_guard<std::mutex> lock(cursor_mutex);
3683 
3684  for(auto& iter : cursor_map)
3685  {
3686  Yetani::Cursor& cursor = iter.second;
3687 
3688  if(cursor.next_frame_time <= time_now)
3689  {
3690  const int64_t time_over = time_now - cursor.next_frame_time;
3691  cursor.next_frame_time = time_now + cursor.time_per_frame - time_over;
3692 
3693  cursor.buffer_index = (cursor.buffer_index + 1) % cursor.buffer_vector.size();
3694 
3695  wl_surface_attach(cursor.wl_surface, cursor.buffer_vector[cursor.buffer_index], 0, 0);
3696  wl_surface_damage(cursor.wl_surface
3697  , 0, 0
3698  , cursor.width, cursor.height
3699  );
3700 
3701  wl_surface_commit(cursor.wl_surface);
3702  }
3703  }
3704 }
3705 
3706 
3747 std::error_code Yetani::cursorCreate(const std::string& name
3748  , const Yetani::CursorConfig& config
3749  ) noexcept
3750 {
3751  if(name.empty())
3752  {
3753  return ZAKERO_YETANI__ERROR(Error_Cursor_Name_Is_Invalid);
3754  }
3755 
3756  if(cursor_map.contains(name) == true)
3757  {
3758  return ZAKERO_YETANI__ERROR(Error_Cursor_Already_Exists);
3759  }
3760 
3761  if(config.size.width <= 0 || config.size.height <= 0)
3762  {
3763  return ZAKERO_YETANI__ERROR(Error_Cursor_Size_Too_Small);
3764  }
3765 
3766  if(config.image_data.empty())
3767  {
3768  return ZAKERO_YETANI__ERROR(Error_Cursor_Image_Data_Is_Empty);
3769  }
3770  else if(config.image_data.size() > 1)
3771  {
3772  if(config.time_per_frame.count() <= 0)
3773  {
3774  return ZAKERO_YETANI__ERROR(Error_Cursor_Frame_Time_Too_Small);
3775  }
3776 
3777  if(config.time_per_frame.count() > Size_Max)
3778  {
3779  return ZAKERO_YETANI__ERROR(Error_Cursor_Frame_Time_Too_Large);
3780  }
3781  }
3782 
3783  std::error_code error = cursorCreateCursor(name, config);
3784 
3785  return error;
3786 }
3787 
3788 
3799 std::error_code Yetani::cursorCreateCursor(const std::string& cursor_name
3800  , const Yetani::CursorConfig& cursor_config
3801  ) noexcept
3802 {
3803  const uint8_t bytes_per_pixel = shmFormatBytesPerPixel(cursor_config.format);
3804  const size_t frame_count = cursor_config.image_data.size();
3805 
3806  Yetani::Cursor cursor =
3807  { .buffer_vector = { frame_count, nullptr }
3808  , .format = cursor_config.format
3809  , .next_frame_time = ZAKERO_STEADY_TIME_NOW(milliseconds)
3810  , .buffer_index = 0
3811  , .time_per_frame = uint32_t(cursor_config.time_per_frame.count())
3812  , .width = cursor_config.size.width
3813  , .height = cursor_config.size.height
3814  , .hotspot_x = cursor_config.hotspot_x
3815  , .hotspot_y = cursor_config.hotspot_y
3816  };
3817 
3818  if(cursor.time_per_frame == 0)
3819  {
3820  cursor.time_per_frame = Size_Max;
3821  }
3822 
3823  cursor.wl_surface = wl_compositor_create_surface(compositor);
3824 
3825  const int stride = cursor.width * bytes_per_pixel;
3826  const size_t image_size = stride * cursor.height;
3827 
3828  for(size_t i = 0; i < frame_count; i++)
3829  {
3830  std::error_code error;
3831 
3832  off_t offset = cursor_memory_pool.alloc(image_size, error);
3833  if(error)
3834  {
3835  while(i > 0)
3836  {
3837  i--;
3838 
3839  struct wl_buffer* buffer = cursor.buffer_vector[i];
3840  cursor.buffer_vector[i] = nullptr;
3841 
3842  off_t offset = (off_t)wl_buffer_get_user_data(buffer);
3843  wl_buffer_destroy(buffer);
3844 
3845  cursor_memory_pool.free(offset);
3846  }
3847 
3848  return error;
3849  }
3850 
3851  uint32_t* p = (uint32_t*)cursor_memory_pool.addressOf(offset);
3852  memcpy(p, (uint8_t*)cursor_config.image_data[i], image_size);
3853 
3854  cursor.buffer_vector[i] = wl_shm_pool_create_buffer(cursor_shm_pool
3855  , offset
3856  , cursor.width
3857  , cursor.height
3858  , stride
3859  , cursor.format
3860  );
3861 
3862  wl_buffer_set_user_data(cursor.buffer_vector[i], (void*)offset);
3863  }
3864 
3865  wl_surface_attach(cursor.wl_surface, cursor.buffer_vector[0], 0, 0);
3866  wl_surface_commit(cursor.wl_surface);
3867 
3868  std::lock_guard<std::mutex> lock(cursor_mutex);
3869 
3870  cursor_map[cursor_name] = cursor;
3871 
3872  return ZAKERO_YETANI__ERROR(Error_None);
3873 }
3874 
3875 
3886 std::error_code Yetani::cursorDestroy(const std::string& name
3887  ) noexcept
3888 {
3889  Yetani::Cursor cursor;
3890 
3891  {
3892  std::lock_guard<std::mutex> lock(cursor_mutex);
3893 
3894  if(cursor_map.contains(name) == false)
3895  {
3896  return ZAKERO_YETANI__ERROR(Error_Cursor_Does_Not_Exist);
3897  }
3898 
3899  cursor = cursor_map[name];
3900 
3901  cursor_map.erase(name);
3902  }
3903 
3904  auto iter = std::begin(cursor_surface_map);
3905  auto iter_end = std::end(cursor_surface_map);
3906  while(iter != iter_end)
3907  {
3908  if(cursor.wl_surface == iter->second.wl_surface)
3909  {
3910  iter = cursor_surface_map.erase(iter);
3911  }
3912  else
3913  {
3914  iter++;
3915  }
3916  }
3917 
3918  if(cursor.wl_surface)
3919  {
3920  wl_surface_destroy(cursor.wl_surface);
3921  cursor.wl_surface = nullptr;
3922  }
3923 
3924  for(wl_buffer* buffer : cursor.buffer_vector)
3925  {
3926  off_t offset = (off_t)wl_buffer_get_user_data(buffer);
3927  wl_buffer_destroy(buffer);
3928 
3929  cursor_memory_pool.free(offset);
3930  }
3931 
3932  return ZAKERO_YETANI__ERROR(Error_None);
3933 }
3934 
3935 
3944 void Yetani::cursorEnter(wl_pointer* wl_pointer
3945  , uint32_t serial
3946  , struct wl_surface* wl_surface
3947  ) noexcept
3948 {
3949  std::lock_guard<std::mutex> lock(cursor_mutex);
3950 
3951  cursor_pointer = wl_pointer;
3952 
3953  if(cursor_surface_map.contains(wl_surface) == false)
3954  {
3955  return;
3956  }
3957 
3958  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
3959 
3960  cursor_surface.wl_pointer = wl_pointer;
3961  cursor_surface.serial = serial;
3962 
3963  if(cursor_surface.is_visible)
3964  {
3965  wl_pointer_set_cursor(cursor_surface.wl_pointer
3966  , cursor_surface.serial
3967  , cursor_surface.wl_surface
3968  , cursor_surface.hotspot_x
3969  , cursor_surface.hotspot_y
3970  );
3971  }
3972  else
3973  {
3974  wl_pointer_set_cursor(cursor_surface.wl_pointer
3975  , cursor_surface.serial
3976  , nullptr
3977  , 0
3978  , 0
3979  );
3980  }
3981 }
3982 
3983 
3993 void Yetani::cursorLeave(struct wl_surface* wl_surface
3994  ) noexcept
3995 {
3996  std::lock_guard<std::mutex> lock(cursor_mutex);
3997 
3998  cursor_pointer = nullptr;
3999 
4000  if(cursor_surface_map.contains(wl_surface) == false)
4001  {
4002  return;
4003  }
4004 
4005  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4006 
4007  cursor_surface.wl_pointer = nullptr;
4008  cursor_surface.serial = 0;
4009 }
4010 
4011 
4019 void Yetani::cursorHide(struct wl_surface* wl_surface
4020  ) noexcept
4021 {
4022  std::lock_guard<std::mutex> lock(cursor_mutex);
4023 
4024  if(cursor_surface_map.contains(wl_surface) == false)
4025  {
4026  return;
4027  }
4028 
4029  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4030 
4031  cursor_surface.is_visible = false;
4032 
4033  if(cursor_surface.wl_pointer != nullptr)
4034  {
4035  wl_pointer_set_cursor(cursor_surface.wl_pointer
4036  , cursor_surface.serial
4037  , nullptr
4038  , 0
4039  , 0
4040  );
4041  }
4042 }
4043 
4044 
4052 void Yetani::cursorShow(struct wl_surface* wl_surface
4053  ) noexcept
4054 {
4055  std::lock_guard<std::mutex> lock(cursor_mutex);
4056 
4057  if(cursor_surface_map.contains(wl_surface) == false)
4058  {
4059  return;
4060  }
4061 
4062  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4063 
4064  cursor_surface.is_visible = true;
4065 
4066  if(cursor_surface.wl_pointer != nullptr)
4067  {
4068  wl_pointer_set_cursor(cursor_surface.wl_pointer
4069  , cursor_surface.serial
4070  , cursor_surface.wl_surface
4071  , cursor_surface.hotspot_x
4072  , cursor_surface.hotspot_y
4073  );
4074  }
4075 }
4076 
4077 
4088 bool Yetani::cursorIsHidden(struct wl_surface* wl_surface
4089  ) const noexcept
4090 {
4091  std::lock_guard<std::mutex> lock(cursor_mutex);
4092 
4093  if(cursor_surface_map.contains(wl_surface) == false)
4094  {
4095  return true;
4096  }
4097 
4098  const Yetani::CursorSurface& cursor_surface = cursor_surface_map.at(wl_surface);
4099 
4100  return !(cursor_surface.is_visible);
4101 }
4102 
4103 
4111 void Yetani::cursorSetup() noexcept
4112 {
4113  cursor_map.clear();
4114 
4115  uint64_t bytes = zakero::convert((uint64_t)4, zakero::Storage::Kilobyte, zakero::Storage::Byte);
4116  cursor_memory_pool.init(bytes, true, zakero::MemoryPool::Alignment::Bits_32);
4117 
4118  cursor_memory_pool.sizeOnChange([&](size_t new_size)
4119  {
4120  wl_shm_pool_resize(cursor_shm_pool, new_size);
4121  });
4122 
4123  cursor_shm_pool = wl_shm_create_pool(shm, cursor_memory_pool.fd(), cursor_memory_pool.size());
4124 }
4125 
4126 
4134 void Yetani::cursorTeardown() noexcept
4135 {
4136  while(cursor_map.empty() == false)
4137  {
4138  const auto& iter = cursor_map.begin();
4139 
4140  const std::string& name = iter->first;
4141 
4142  cursorDestroy(name);
4143  }
4144 
4145  if(cursor_shm_pool != nullptr)
4146  {
4147  wl_shm_pool_destroy(cursor_shm_pool);
4148  }
4149 }
4150 
4151 
4163 std::error_code Yetani::cursorAttach(const std::string& cursor_name
4164  , struct wl_surface* wl_surface
4165  ) noexcept
4166 {
4167  std::lock_guard<std::mutex> lock(cursor_mutex);
4168 
4169  if(cursor_map.contains(cursor_name) == false)
4170  {
4171  return ZAKERO_YETANI__ERROR(Error_Cursor_Does_Not_Exist);
4172  }
4173 
4174  if(cursor_surface_map.contains(wl_surface) == false)
4175  {
4176  cursor_surface_map[wl_surface] =
4177  { .wl_pointer = cursor_pointer
4178  , .wl_surface = nullptr
4179  , .serial = 0
4180  , .hotspot_x = 0
4181  , .hotspot_y = 0
4182  , .is_visible = true
4183  };
4184  }
4185 
4186  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4187  Yetani::Cursor& cursor = cursor_map[cursor_name];
4188 
4189  cursor_surface.wl_surface = cursor.wl_surface;
4190  cursor_surface.hotspot_x = cursor.hotspot_x;
4191  cursor_surface.hotspot_y = cursor.hotspot_y;
4192 
4193  if(cursor_surface.wl_pointer != nullptr)
4194  {
4195  if(cursor_surface.is_visible)
4196  {
4197  wl_pointer_set_cursor(cursor_surface.wl_pointer
4198  , cursor_surface.serial
4199  , cursor_surface.wl_surface
4200  , cursor_surface.hotspot_x
4201  , cursor_surface.hotspot_y
4202  );
4203  }
4204  else
4205  {
4206  wl_pointer_set_cursor(cursor_surface.wl_pointer
4207  , cursor_surface.serial
4208  , nullptr
4209  , 0
4210  , 0
4211  );
4212  }
4213  }
4214 
4215  return ZAKERO_YETANI__ERROR(Error_None);
4216 }
4217 
4218 
4230 std::error_code Yetani::cursorDetach(struct wl_surface* wl_surface
4231  ) noexcept
4232 {
4233  std::lock_guard<std::mutex> lock(cursor_mutex);
4234 
4235  if(cursor_surface_map.contains(wl_surface) == false)
4236  {
4237  return ZAKERO_YETANI__ERROR(Error_Cursor_Not_Attached);
4238  }
4239 
4240  Yetani::CursorSurface& cursor_surface = cursor_surface_map[wl_surface];
4241 
4242  if(cursor_surface.wl_pointer != nullptr)
4243  {
4244  wl_pointer_set_cursor(cursor_surface.wl_pointer
4245  , cursor_surface.serial
4246  , nullptr
4247  , 0
4248  , 0
4249  );
4250  }
4251 
4252  cursor_surface_map.erase(wl_surface);
4253 
4254  return ZAKERO_YETANI__ERROR(Error_None);
4255 }
4256 
4257 // }}}
4258 // {{{ Event Loop
4259 
4260 //#define ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4261 
4270 void Yetani::eventLoopStart() noexcept
4271 {
4272  event_loop = std::jthread(&Yetani::eventLoop, this);
4273 
4274  while(event_loop_is_running.load() == false)
4275  {
4276  // Wait for the thread to start
4277  std::this_thread::sleep_for(std::chrono::nanoseconds(42));
4278  }
4279 
4280  #ifdef ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4281  int policy = SCHED_FIFO;
4282  int priority_min = sched_get_priority_min(policy);
4283  int priority_max = sched_get_priority_max(policy);
4284 
4285  sched_param sched =
4286  { .sched_priority = (priority_min + priority_max) / 2
4287  };
4288 
4289  pthread_setschedparam(event_loop.native_handle(), policy, &sched);
4290  #endif
4291 }
4292 
4293 
4321 void Yetani::eventLoop(std::stop_token thread_token
4322  , Yetani* yetani
4323  ) noexcept
4324 {
4325  struct pollfd fd_status =
4326  { .fd = wl_display_get_fd(yetani->display)
4327  , .events = POLLIN | POLLOUT
4328  , .revents = 0
4329  };
4330 
4331  yetani->event_loop_is_running.store(true);
4332 
4333  // Handle events and render window contents
4334  while(thread_token.stop_requested() == false)
4335  {
4336  poll(&fd_status, 1, 1);
4337 
4338  if(fd_status.revents & POLLIN)
4339  {
4340  wl_display_dispatch(yetani->display);
4341  }
4342 
4343  yetani->cursorAnimate();
4344 
4345  keyboardRepeat(yetani->keyboard);
4346 
4347  if(fd_status.revents & POLLOUT)
4348  {
4349  wl_display_flush(yetani->display);
4350  }
4351 
4352  #ifdef ZAKERO_YETANI__ENABLE_THREAD_SCHEDULER
4353  std::this_thread::yield();
4354  #endif
4355  }
4356 
4357  yetani->event_loop_is_running.store(false);
4358 }
4359 
4360 // }}}
4361 // {{{ Shared Memory
4362 
4373 const Yetani::VectorShmFormat& Yetani::shmFormatAvailable() const noexcept
4374 {
4375  return shm_format_vector;
4376 }
4377 
4378 
4390 uint8_t Yetani::shmFormatBytesPerPixel(const wl_shm_format shm_format
4391  ) noexcept
4392 {
4393  switch(shm_format)
4394  {
4395 #define X(value_, bytes_, desc_) \
4396  case value_: return bytes_;
4397  ZAKERO_YETANI__SHM_FORMAT
4398 #undef X
4399  default: return 0;
4400  }
4401 }
4402 
4403 
4415 std::string Yetani::shmFormatDescription(const wl_shm_format shm_format
4416  ) noexcept
4417 {
4418  switch(shm_format)
4419  {
4420 #define X(value_, bytes_, desc_) \
4421  case value_: return desc_;
4422  ZAKERO_YETANI__SHM_FORMAT
4423 #undef X
4424  default: return "";
4425  }
4426 }
4427 
4428 
4438 std::string Yetani::shmFormatName(const wl_shm_format shm_format
4439  ) noexcept
4440 {
4441  switch(shm_format)
4442  {
4443 #define X(value_, bytes_, desc_) \
4444  case value_: return #value_;
4445  ZAKERO_YETANI__SHM_FORMAT
4446 #undef X
4447  default: return "";
4448  }
4449 }
4450 
4451 // }}}
4452 // {{{ Utility
4453 
4454 
4455 // }}}
4456 // {{{ Wayland : Buffer
4457 
4498 struct wl_buffer* Yetani::bufferCreate(Yetani::SurfaceSize& surface_size
4499  , Yetani::Window::Memory* window_memory
4500  , Yetani::Buffer* buffer
4501  ) noexcept
4502 {
4503  off_t offset = window_memory->memory_pool.alloc(surface_size.in_bytes);
4504 
4505  struct wl_buffer* wl_buffer = wl_shm_pool_create_buffer(window_memory->wl_shm_pool
4506  , offset
4507  , surface_size.width
4508  , surface_size.height
4509  , surface_size.stride
4510  , surface_size.pixel_format
4511  );
4512 
4513  wl_buffer_set_user_data(wl_buffer, buffer);
4514 
4515  buffer->mutex.lock();
4516  {
4517  buffer->map[wl_buffer] =
4518  { .memory_pool = &window_memory->memory_pool
4519  , .offset = offset
4520  };
4521  }
4522  buffer->mutex.unlock();
4523 
4524  return wl_buffer;
4525 }
4526 
4527 
4539 struct wl_buffer* Yetani::bufferCreateAndRelease(Yetani* yetani
4540  , Yetani::SurfaceSize& surface_size
4541  , Yetani::Window::Memory* window_memory
4542  ) noexcept
4543 {
4544  struct wl_buffer* wl_buffer = bufferCreate(surface_size, window_memory, &yetani->buffer);
4545 
4546  wl_buffer_add_listener(wl_buffer
4547  , &Yetani::buffer_listener
4548  , &yetani->buffer
4549  );
4550 
4551  return wl_buffer;
4552 }
4553 
4554 
4564 void Yetani::bufferDestroy(struct wl_buffer*& wl_buffer
4565  ) noexcept
4566 {
4567  Yetani::Buffer* buffer = (Yetani::Buffer*)wl_buffer_get_user_data(wl_buffer);
4568 
4569  wl_buffer_destroy(wl_buffer);
4570 
4571  buffer->mutex.lock();
4572  {
4573  BufferData& buffer_data = buffer->map[wl_buffer];
4574 
4575  buffer_data.memory_pool->free(buffer_data.offset);
4576 
4577  buffer->map.erase(wl_buffer);
4578  }
4579  buffer->mutex.unlock();
4580 
4581  wl_buffer = nullptr;
4582 }
4583 
4584 // }}}
4585 // {{{ Wayland : Output
4586 
4682 Yetani::Output Yetani::output(Yetani::OutputId output_id
4683  ) const noexcept
4684 {
4685  std::lock_guard<std::mutex> lock(output_data.mutex);
4686 
4687  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4688  {
4689  ZAKERO_YETANI__DEBUG
4690  << "Invalid output_id: "
4691  << std::to_string(output_id)
4692  ;
4693 
4694  return {};
4695  }
4696 
4697  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4698 
4699  return output_data.output_map.at(wl_output);
4700 }
4701 
4702 
4714 Yetani::VectorOutputId Yetani::outputVector() const noexcept
4715 {
4716  Yetani::VectorOutputId vector;
4717 
4718  std::lock_guard<std::mutex> lock(output_data.mutex);
4719 
4720  for(const auto& iter : output_data.outputid_to_wloutput)
4721  {
4722  vector.push_back(iter.first);
4723  }
4724 
4725  return vector;
4726 }
4727 
4728 
4740 std::string Yetani::outputSubpixelName(int32_t subpixel_format
4741  ) noexcept
4742 {
4743  switch(subpixel_format)
4744  {
4745 #define X(value_, name_) \
4746  case value_: return name_;
4747  ZAKERO_YETANI__OUTPUT_SUBPIXEL
4748 #undef X
4749  default: return "";
4750  }
4751 }
4752 
4753 
4765 std::string Yetani::outputTransformName(int32_t transform
4766  ) noexcept
4767 {
4768  switch(transform)
4769  {
4770 #define X(value_, name_) \
4771  case value_: return name_;
4772  ZAKERO_YETANI__OUTPUT_TRANSFORM
4773 #undef X
4774  default: return "";
4775  }
4776 }
4777 
4778 
4789 Yetani::PointMm Yetani::outputConvertToMm(const Yetani::OutputId output_id
4790  , const Yetani::PointPixel& point
4791  ) const noexcept
4792 {
4793  std::lock_guard<std::mutex> lock(output_data.mutex);
4794 
4795  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4796  {
4797  return { 0, 0 };
4798  }
4799 
4800  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4801  const Yetani::Output& output = output_data.output_map.at(wl_output);
4802 
4803  auto p = convertPixelToMm(output, point.x, point.y);
4804 
4805  return { point.time, p.first, p.second };
4806 }
4807 
4808 
4819 Yetani::PointPercent Yetani::outputConvertToPercent(const Yetani::OutputId output_id
4820  , const Yetani::PointPixel& point
4821  ) const noexcept
4822 {
4823  std::lock_guard<std::mutex> lock(output_data.mutex);
4824 
4825  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4826  {
4827  return { 0, 0 };
4828  }
4829 
4830  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4831  const Yetani::Output& output = output_data.output_map.at(wl_output);
4832 
4833  auto p = convertPixelToPercent(output, point.x, point.y);
4834 
4835  return { point.time, p.first, p.second };
4836 }
4837 
4838 
4849 Yetani::PointPixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4850  , const Yetani::PointMm& point
4851  ) const noexcept
4852 {
4853  std::lock_guard<std::mutex> lock(output_data.mutex);
4854 
4855  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4856  {
4857  return { 0, 0 };
4858  }
4859 
4860  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4861  const Yetani::Output& output = output_data.output_map.at(wl_output);
4862 
4863  auto p = convertMmToPixel(output, point.x, point.y);
4864 
4865  return { point.time, p.first, p.second };
4866 }
4867 
4868 
4879 Yetani::PointPixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4880  , const Yetani::PointPercent& point
4881  ) const noexcept
4882 {
4883  std::lock_guard<std::mutex> lock(output_data.mutex);
4884 
4885  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4886  {
4887  return { 0, 0 };
4888  }
4889 
4890  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4891  const Yetani::Output& output = output_data.output_map.at(wl_output);
4892 
4893  auto p = convertPercentToPixel(output, point.x, point.y);
4894 
4895  return { point.time, p.first, p.second };
4896 }
4897 
4898 
4909 Yetani::SizeMm Yetani::outputConvertToMm(const Yetani::OutputId output_id
4910  , const Yetani::SizePixel& size
4911  ) const noexcept
4912 {
4913  std::lock_guard<std::mutex> lock(output_data.mutex);
4914 
4915  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4916  {
4917  return { 0, 0 };
4918  }
4919 
4920  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4921  const Yetani::Output& output = output_data.output_map.at(wl_output);
4922 
4923  auto p = convertPixelToMm(output, size.width, size.height);
4924 
4925  return { p.first, p.second };
4926 }
4927 
4928 
4939 Yetani::SizePercent Yetani::outputConvertToPercent(const Yetani::OutputId output_id
4940  , const Yetani::SizePixel& size
4941  ) const noexcept
4942 {
4943  std::lock_guard<std::mutex> lock(output_data.mutex);
4944 
4945  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4946  {
4947  return { 0, 0 };
4948  }
4949 
4950  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4951  const Yetani::Output& output = output_data.output_map.at(wl_output);
4952 
4953  auto p = convertPixelToPercent(output, size.width, size.height);
4954 
4955  return { p.first, p.second };
4956 }
4957 
4958 
4968 Yetani::SizePixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4969  , const Yetani::SizeMm& size
4970  ) const noexcept
4971 {
4972  std::lock_guard<std::mutex> lock(output_data.mutex);
4973 
4974  if(output_data.outputid_to_wloutput.contains(output_id) == false)
4975  {
4976  return { 0, 0 };
4977  }
4978 
4979  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
4980  const Yetani::Output& output = output_data.output_map.at(wl_output);
4981 
4982  auto p = convertMmToPixel(output, size.width, size.height);
4983 
4984  return { p.first, p.second };
4985 }
4986 
4987 
4997 Yetani::SizePixel Yetani::outputConvertToPixel(const Yetani::OutputId output_id
4998  , const Yetani::SizePercent& size
4999  ) const noexcept
5000 {
5001  std::lock_guard<std::mutex> lock(output_data.mutex);
5002 
5003  if(output_data.outputid_to_wloutput.contains(output_id) == false)
5004  {
5005  return { 0, 0 };
5006  }
5007 
5008  struct wl_output* wl_output = output_data.outputid_to_wloutput.at(output_id);
5009  const Yetani::Output& output = output_data.output_map.at(wl_output);
5010 
5011  auto p = convertPercentToPixel(output, size.width, size.height);
5012 
5013  return { p.first, p.second };
5014 }
5015 
5016 
5026 void Yetani::outputOnAdd(LambdaOutputId lambda
5027  ) noexcept
5028 {
5029  if(lambda == nullptr)
5030  {
5031  on_output_add = LambdaOutputId_DoNothing;
5032  }
5033  else
5034  {
5035  on_output_add = lambda;
5036  }
5037 }
5038 
5039 
5049 void Yetani::outputOnChange(LambdaOutputId lambda
5050  ) noexcept
5051 {
5052  if(lambda == nullptr)
5053  {
5054  on_output_change = LambdaOutputId_DoNothing;
5055  }
5056  else
5057  {
5058  on_output_change = lambda;
5059  }
5060 }
5061 
5062 
5072 void Yetani::outputOnRemove(LambdaOutputId lambda
5073  ) noexcept
5074 {
5075  if(lambda == nullptr)
5076  {
5077  on_output_remove = LambdaOutputId_DoNothing;
5078  }
5079  else
5080  {
5081  on_output_remove = lambda;
5082  }
5083 }
5084 
5085 
5094 void Yetani::convertPixel(struct wl_surface* wl_surface
5095  , const int32_t pixel_xw
5096  , const int32_t pixel_yh
5097  , float& mm_xw
5098  , float& mm_yh
5099  , float& pc_xw
5100  , float& pc_yh
5101  ) const noexcept
5102 {
5103  std::lock_guard<std::mutex> lock(output_data.mutex);
5104 
5105  const Yetani::VectorWlOutput& vector = output_data.surface_output_map.at(wl_surface);
5106  struct wl_output* wl_output = vector.front();
5107  const Yetani::Output& output = output_data.output_map.at(wl_output);
5108 
5109  auto mm = convertPixelToMm(output, pixel_xw, pixel_yh);
5110  mm_xw = mm.first;
5111  mm_yh = mm.second;
5112 
5113  auto pc = convertPixelToPercent(output, pixel_xw, pixel_yh);
5114  pc_xw = pc.first;
5115  pc_yh = pc.second;
5116 }
5117 
5118 
5130 std::pair<float, float> Yetani::convertPixelToMm(const Yetani::Output& output
5131  , int32_t xw
5132  , int32_t yh
5133  ) const noexcept
5134 {
5135  const float ratio_h = output.pixels_per_mm_horizontal;
5136  const float ratio_v = output.pixels_per_mm_vertical;
5137 
5138  return
5139  { xw / ratio_h
5140  , yh / ratio_v
5141  };
5142 }
5143 
5144 
5156 std::pair<float, float> Yetani::convertPixelToPercent(const Yetani::Output& output
5157  , int32_t xw
5158  , int32_t yh
5159  ) const noexcept
5160 {
5161  return
5162  { float(xw) / output.width
5163  , float(yh) / output.height
5164  };
5165 }
5166 
5167 
5179 std::pair<int32_t, int32_t> Yetani::convertMmToPixel(const Yetani::Output& output
5180  , float xw
5181  , float yh
5182  ) const noexcept
5183 {
5184  const float ratio_h = output.pixels_per_mm_horizontal;
5185  const float ratio_v = output.pixels_per_mm_vertical;
5186 
5187  return
5188  { int32_t(xw * ratio_h)
5189  , int32_t(yh * ratio_v)
5190  };
5191 }
5192 
5193 
5205 std::pair<int32_t, int32_t> Yetani::convertPercentToPixel(const Yetani::Output& output
5206  , float xw
5207  , float yh
5208  ) const noexcept
5209 {
5210  return
5211  { int32_t(xw * output.width)
5212  , int32_t(yh * output.height)
5213  };
5214 }
5215 
5216 
5228 void Yetani::outputNotifySurface(Yetani* yetani
5229  , struct wl_output* wl_output
5230  , struct wl_surface* wl_surface
5231  ) noexcept
5232 {
5233  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
5234  if(surface_extent.preferred_unit == Yetani::SizeUnit::Pixel)
5235  {
5236  return;
5237  }
5238 
5239  Yetani::OutputData& output_data = yetani->output_data;
5240 
5241  std::lock_guard<std::mutex> lock(output_data.mutex);
5242 
5243  Yetani::VectorWlOutput& output_vector = output_data.surface_output_map[wl_surface];
5244 
5245  struct wl_output* output_current = output_vector.front();
5246 
5247  if(output_current != wl_output)
5248  {
5249  return;
5250  }
5251 
5252  Yetani::Output& output = output_data.output_map.at(wl_output);
5253  Yetani::SizePixel new_size = surface_extent.size_pixel;
5254 
5255  if(surface_extent.preferred_unit == Yetani::SizeUnit::Millimeter)
5256  {
5257  auto p = yetani->convertMmToPixel(output, surface_extent.size_mm.width, surface_extent.size_mm.height);
5258  new_size = { p.first, p.second };
5259  }
5260  else if(surface_extent.preferred_unit == Yetani::SizeUnit::Percent)
5261  {
5262  auto p = yetani->convertPercentToPixel(output, surface_extent.size_percent.width, surface_extent.size_percent.height);
5263  new_size = { p.first, p.second };
5264  }
5265 
5266  if(new_size.width <= 0)
5267  {
5268  new_size.width = 1;
5269  }
5270 
5271  if(new_size.height <= 0)
5272  {
5273  new_size.height = 1;
5274  }
5275 
5276  yetani->surface_resize_mutex_map[wl_surface].lock();
5277  {
5278  surface_extent.size_pixel = new_size;
5279  surfaceCalculateSize(yetani, wl_surface, new_size);
5280  }
5281  yetani->surface_resize_mutex_map[wl_surface].unlock();
5282 }
5283 
5284 // }}}
5285 // {{{ Wayland : Seat
5286 
5319 void Yetani::seatDestroy(struct wl_seat*& wl_seat
5320  ) noexcept
5321 {
5322  Yetani::Seat& seat = seat_map[wl_seat];
5323 
5324  if(seat.wl_keyboard != nullptr)
5325  {
5326  wl_keyboard_release(seat.wl_keyboard);
5327  seat.wl_keyboard = nullptr;
5328  }
5329 
5330  if(seat.wl_pointer != nullptr)
5331  {
5332  wl_pointer_release(seat.wl_pointer);
5333  seat.wl_pointer = nullptr;
5334  }
5335 
5336  if(seat.wl_touch != nullptr)
5337  {
5338  wl_touch_release(seat.wl_touch);
5339  seat.wl_touch = nullptr;
5340  }
5341 
5342  seat_map.erase(wl_seat);
5343 
5344  wl_seat_release(wl_seat);
5345 
5346  wl_seat = nullptr;
5347 }
5348 
5349 // }}}
5350 // {{{ Wayland : Seat : Keyboard
5351 
5425 int32_t Yetani::keyRepeatDelay() const noexcept
5426 {
5427  return keyboard.repeat_delay;
5428 }
5429 
5430 
5439 int32_t Yetani::keyRepeatRate() const noexcept
5440 {
5441  return 1000 / keyboard.repeat_rate;
5442 }
5443 
5444 
5448 void Yetani::keyboardDestroy(Yetani::Keyboard& keyboard
5449  ) noexcept
5450 {
5451  if(keyboard.keymap != nullptr)
5452  {
5453  munmap(keyboard.keymap, keyboard.keymap_size);
5454  }
5455 
5456  keyboard.wl_surface = nullptr;
5457  keyboard.event = nullptr;
5458  keyboard.modifier = { 0 };
5459  keyboard.repeat_rate = 0;
5460  keyboard.repeat_delay = {};
5461  keyboard.keymap = nullptr;
5462  keyboard.keymap_size = 0;
5463 }
5464 
5465 
5472 void Yetani::keyboardRepeat(Yetani::Keyboard& keyboard
5473  ) noexcept
5474 {
5475  auto now = std::chrono::steady_clock::now();
5476 
5477  for(auto& iter : keyboard.repeat_map)
5478  {
5479  Yetani::KeyRepeatData& key_repeat = iter.second;
5480 
5481  if(now >= key_repeat.trigger_time)
5482  {
5483  uint32_t key_code = iter.first;
5484 
5485  Yetani::Key key =
5486  { .time = key_repeat.base_time
5487  , .code = key_code
5488  , .state = Yetani::KeyState::Repeat
5489  };
5490 
5491  keyboard.event->on_key(key, keyboard.modifier);
5492 
5493  key_repeat.trigger_time = now
5494  + std::chrono::milliseconds(keyboard.repeat_rate)
5495  - (now - key_repeat.trigger_time)
5496  ;
5497  key_repeat.base_time += keyboard.repeat_rate;
5498  }
5499  }
5500 }
5501 
5502 
5510 void Yetani::keyboardRepeatAdd(Yetani::Keyboard& keyboard
5511  , uint32_t key_code
5512  , uint32_t time
5513  ) noexcept
5514 {
5515  auto trigger_time = std::chrono::steady_clock::now()
5516  + std::chrono::milliseconds(keyboard.repeat_delay)
5517  ;
5518 
5519  keyboard.repeat_map[key_code] =
5520  { .trigger_time = trigger_time
5521  , .base_time = time + keyboard.repeat_delay
5522  };
5523 }
5524 
5525 
5532 void Yetani::keyboardRepeatReleaseAll(Yetani::Keyboard& keyboard
5533  ) noexcept
5534 {
5535  while(keyboard.repeat_map.empty() == false)
5536  {
5537  auto iter = keyboard.repeat_map.begin();
5538 
5539  uint32_t key_code = iter->first;
5540 
5541  Yetani::Key key =
5542  { .time = 0
5543  , .code = key_code
5544  , .state = Yetani::KeyState::Released
5545  };
5546 
5547  keyboard.event->on_key(key, keyboard.modifier);
5548 
5549  keyboard.repeat_map.erase(iter);
5550  }
5551 }
5552 
5553 
5560 void Yetani::keyboardRepeatRemove(Yetani::Keyboard& keyboard
5561  , uint32_t key_code
5562  ) noexcept
5563 {
5564  keyboard.repeat_map.erase(key_code);
5565 }
5566 
5567 // }}}
5568 // {{{ Wayland : Seat : Pointer
5569 
5585 void Yetani::pointerClear(Yetani::Pointer& pointer
5586  ) noexcept
5587 {
5588  pointer.enter_surface = nullptr;
5589  pointer.enter_point = { 0, 0, 0 };
5590  pointer.leave_surface = nullptr;
5591  pointer.motion_point = { 0, 0, 0 };
5592  pointer.button_event_code = 0;
5593  pointer.button_is_pressed = false;
5594  pointer.button_time = 0;
5595  pointer.axis.time = 0;
5596  pointer.axis.type = Yetani::PointerAxisType::Unknown;
5597  pointer.axis.distance = 0;
5598  pointer.axis.source = Yetani::PointerAxisSource::Unknown;
5599  pointer.axis.steps = 0;
5600 }
5601 
5602 // }}}
5603 // {{{ Wayland : Surface
5604 
5642 void Yetani::surfaceCalculateSize(Yetani* yetani
5643  , struct wl_surface* wl_surface
5644  , const Yetani::SizePixel& size
5645  ) noexcept
5646 {
5647  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
5648  surface_size.width = size.width;
5649  surface_size.height = size.height;
5650  surface_size.stride = size.width * surface_size.bytes_per_pixel;
5651  surface_size.in_bytes = surface_size.stride * surface_size.height;
5652 
5653  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5654  surface_frame.width = size.width;
5655  surface_frame.height = size.height;
5656 }
5657 
5658 
5666 struct wl_surface* Yetani::surfaceCreate(Yetani* yetani
5667  , const wl_shm_format pixel_format
5668  , const Yetani::SizePixel& size
5669  , const bool attach_buffer
5670  , Yetani::Window::Memory& window_memory
5671  ) noexcept
5672 {
5673  struct wl_surface* wl_surface = wl_compositor_create_surface(yetani->compositor);
5674 
5675  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
5676  surface_size.pixel_format = pixel_format;
5677  surface_size.bytes_per_pixel = shmFormatBytesPerPixel(pixel_format);
5678 
5679  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5680  surface_frame.callback = nullptr;
5681  surface_frame.wl_surface = wl_surface;
5682  surface_frame.time_ms = 0;
5683 
5684  surfaceCalculateSize(yetani, wl_surface, size);
5685 
5686  surface_frame.buffer_next = bufferCreateAndRelease(yetani, surface_size, &window_memory);
5687 
5688  if(attach_buffer)
5689  {
5690  wl_surface_attach(surface_frame.wl_surface, surface_frame.buffer_next, 0, 0);
5691 
5692  surface_frame.callback = wl_surface_frame(wl_surface);
5693 
5694  wl_callback_add_listener(surface_frame.callback
5695  , &frame_callback_listener
5696  , &surface_frame
5697  );
5698 
5699  wl_surface_commit(wl_surface);
5700  }
5701 
5702  // A future configuration setting
5703  bool event_keyboard = true;
5704  if(event_keyboard)
5705  {
5706  yetani->keyboard.event_map[wl_surface] =
5707  { .on_enter = Lambda_DoNothing
5708  , .on_leave = Lambda_DoNothing
5709  , .on_key = LambdaKey_DoNothing
5710  };
5711  }
5712 
5713  // A future configuration setting
5714  bool event_pointer = true;
5715  if(event_pointer)
5716  {
5717  yetani->pointer.event_map[wl_surface] =
5718  { .on_axis = LambdaAxis_DoNothing
5719  , .on_axis_discrete = Lambda_DoNothing
5720  , .on_axis_source = Lambda_DoNothing
5721  , .on_axis_stop = Lambda_DoNothing
5722  , .on_button_mm = LambdaButtonMm_DoNothing
5723  , .on_button_percent = LambdaButtonPercent_DoNothing
5724  , .on_button_pixel = LambdaButtonPixel_DoNothing
5725  , .on_enter_mm = LambdaPointMm_DoNothing
5726  , .on_enter_percent = LambdaPointPercent_DoNothing
5727  , .on_enter_pixel = LambdaPointPixel_DoNothing
5728  , .on_leave = Lambda_DoNothing
5729  , .on_motion_mm = LambdaPointMm_DoNothing
5730  , .on_motion_percent = LambdaPointPercent_DoNothing
5731  , .on_motion_pixel = LambdaPointPixel_DoNothing
5732  };
5733  }
5734 
5735  yetani->surface_event_map[wl_surface] =
5736  { .on_size_mm_change = LambdaSizeMm_DoNothing
5737  , .on_size_percent_change = LambdaSizePercent_DoNothing
5738  , .on_size_pixel_change = LambdaSizePixel_DoNothing
5739  };
5740 
5741  wl_surface_add_listener(wl_surface
5742  , &surface_listener
5743  , yetani
5744  );
5745 
5746  return wl_surface;
5747 }
5748 
5749 
5755 void Yetani::surfaceDestroy(Yetani* yetani
5756  , struct wl_surface*& wl_surface
5757  ) noexcept
5758 {
5759  if(wl_surface == nullptr)
5760  {
5761  return;
5762  }
5763 
5764  if(yetani->surface_frame_map.contains(wl_surface))
5765  {
5766  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
5767 
5768  if(surface_frame.callback != nullptr)
5769  {
5770  wl_callback_destroy(surface_frame.callback);
5771  surface_frame.callback = nullptr;
5772  }
5773 
5774  struct wl_buffer* wl_buffer = nullptr;
5775  wl_buffer = surface_frame.buffer_next.exchange(nullptr);
5776 
5777  if(wl_buffer != nullptr)
5778  {
5779  bufferDestroy(wl_buffer);
5780  }
5781  }
5782 
5783  if(yetani->keyboard.event_map.contains(wl_surface))
5784  {
5785  yetani->keyboard.event_map.erase(wl_surface);
5786  }
5787 
5788  if(yetani->pointer.event_map.contains(wl_surface))
5789  {
5790  yetani->pointer.event_map.erase(wl_surface);
5791  }
5792 
5793  yetani->surface_size_map.erase(wl_surface);
5794  yetani->surface_frame_map.erase(wl_surface);
5795  yetani->surface_event_map.erase(wl_surface);
5796 
5797  yetani->cursorDetach(wl_surface);
5798 
5799  wl_surface_destroy(wl_surface);
5800  wl_surface = nullptr;
5801 }
5802 
5803 // }}}
5804 // {{{ Wayland : Listener Handlers : Buffer
5805 
5818 void Yetani::handlerBufferRelease(void* //data
5819  , struct wl_buffer* wl_buffer
5820  ) noexcept
5821 {
5822  Yetani::bufferDestroy(wl_buffer);
5823 }
5824 
5825 // }}}
5826 // {{{ Wayland : Listener Handlers : Keyboard
5827 
5831 void Yetani::handlerKeyboardEnter(void* data
5832  , struct wl_keyboard* // wl_keyboard
5833  , uint32_t // serial
5834  , struct wl_surface* wl_surface
5835  , struct wl_array* key_array
5836  ) noexcept
5837 {
5838  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5839 
5840  if(keyboard.wl_surface != nullptr)
5841  {
5842  keyboardRepeatReleaseAll(keyboard);
5843 
5844  keyboard.event->on_leave();
5845  }
5846 
5847  keyboard.wl_surface = wl_surface;
5848 
5849  if(keyboard.event_map.contains(wl_surface))
5850  {
5851  keyboard.event = &(keyboard.event_map[wl_surface]);
5852  }
5853  else
5854  {
5855  keyboard.event = &(keyboard.event_map[nullptr]);
5856  }
5857 
5858  keyboard.event->on_enter();
5859 
5860  if(key_array->size > 0)
5861  {
5862  Yetani::Key key =
5863  { .time = 0
5864  , .code = 0
5865  , .state = Yetani::KeyState::Pressed
5866  };
5867 
5868  ZAKERO_YETANI__ARRAY_FOR_EACH(uint32_t*, key_iter, key_array)
5869  {
5870  key.code = *key_iter;
5871 
5872  keyboard.event->on_key(key, keyboard.modifier);
5873 
5874  keyboardRepeatAdd(keyboard, key.code, 0);
5875  }
5876  }
5877 }
5878 
5879 
5883 void Yetani::handlerKeyboardKey(void* data
5884  , struct wl_keyboard* // wl_keyboard
5885  , uint32_t // serial
5886  , uint32_t time
5887  , uint32_t key_code
5888  , uint32_t state
5889  ) noexcept
5890 {
5891  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5892 
5893  Yetani::Key key =
5894  { .time = time
5895  , .code = key_code
5896  , .state = (state == WL_KEYBOARD_KEY_STATE_PRESSED)
5899  };
5900 
5901  keyboard.event->on_key(key, keyboard.modifier);
5902 
5903  if(key.state == Yetani::KeyState::Pressed
5904  && keyboard.repeat_rate > 0
5905  )
5906  {
5907  keyboardRepeatAdd(keyboard, key_code, time);
5908  }
5909  else if(key.state == Yetani::KeyState::Released)
5910  {
5911  keyboardRepeatRemove(keyboard, key_code);
5912  }
5913 }
5914 
5915 
5919 void Yetani::handlerKeyboardKeymap(void* data
5920  , struct wl_keyboard* // wl_keyboard
5921  , uint32_t format
5922  , int32_t fd
5923  , uint32_t size
5924  ) noexcept
5925 {
5926  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5927 
5928  if(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
5929  {
5930  if(keyboard.keymap != nullptr)
5931  {
5932  munmap(keyboard.keymap
5933  , keyboard.keymap_size
5934  );
5935  }
5936 
5937  keyboard.keymap = (char*)mmap(nullptr
5938  , size
5939  , PROT_READ
5940  , MAP_NORESERVE | MAP_PRIVATE
5941  , fd
5942  , 0
5943  );
5944  keyboard.keymap_size = size;
5945  }
5946  else // (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP)
5947  {
5948  if(keyboard.keymap != nullptr)
5949  {
5950  munmap(keyboard.keymap
5951  , keyboard.keymap_size
5952  );
5953 
5954  keyboard.keymap = nullptr;
5955  keyboard.keymap_size = 0;
5956  }
5957  }
5958 }
5959 
5960 
5964 void Yetani::handlerKeyboardLeave(void* data
5965  , struct wl_keyboard* // wl_keyboard
5966  , uint32_t // serial
5967  , struct wl_surface* wl_surface
5968  ) noexcept
5969 {
5970  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5971 
5972  if(keyboard.wl_surface == wl_surface)
5973  {
5974  keyboardRepeatReleaseAll(keyboard);
5975 
5976  keyboard.event->on_leave();
5977 
5978  keyboard.event = &(keyboard.event_map[nullptr]);
5979  keyboard.wl_surface = nullptr;
5980  }
5981 }
5982 
5983 
5987 void Yetani::handlerKeyboardModifiers(void* data
5988  , struct wl_keyboard* // wl_keyboard
5989  , uint32_t // serial
5990  , uint32_t mods_pressed
5991  , uint32_t mods_latched
5992  , uint32_t mods_locked
5993  , uint32_t group
5994  ) noexcept
5995 {
5996  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
5997 
5998  keyboard.modifier.pressed = mods_pressed;
5999  keyboard.modifier.latched = mods_latched;
6000  keyboard.modifier.locked = mods_locked;
6001  keyboard.modifier.group = group;
6002 }
6003 
6004 
6008 void Yetani::handlerKeyboardRepeatInfo(void* data
6009  , struct wl_keyboard* // wl_keyboard
6010  , int32_t rate
6011  , int32_t delay
6012  ) noexcept
6013 {
6014  Yetani::Keyboard& keyboard = *((Yetani::Keyboard*)data);
6015 
6016  keyboard.repeat_delay = delay;
6017  keyboard.repeat_rate = 1000 / rate;
6018 }
6019 
6020 // }}}
6021 // {{{ Wayland : Listener Handlers : Output
6022 
6026 void Yetani::handlerOutputDone(void* data
6027  , struct wl_output* wl_output
6028  ) noexcept
6029 {
6030  Yetani* yetani = (Yetani*)data;
6031  Yetani::Output& output = yetani->output_data.output_map[wl_output];
6032  Yetani::Output& changes = yetani->output_changes_map[wl_output];
6033  Yetani::OutputId output_id = yetani->output_data.wloutput_to_outputid[wl_output];
6034 
6062  output = changes;
6063  output.pixels_per_mm_horizontal = output.width / float(output.physical_width_mm);
6064  output.pixels_per_mm_vertical = output.height / float(output.physical_height_mm);
6065 
6066  ZAKERO_YETANI__DEBUG << "\n" << to_string(output) << "\n";
6067 
6068  switch(yetani->output_state_map[wl_output])
6069  {
6070  case Yetani::OutputState::Done:
6071  // Do Nothing
6072  break;
6073 
6074  case Yetani::OutputState::Added:
6075  yetani->on_output_add(output_id);
6076  break;
6077 
6078  case Yetani::OutputState::Changed:
6079  yetani->on_output_change(output_id);
6080 
6081  for(auto wl_surface : yetani->output_notify_surface_vector)
6082  {
6083  outputNotifySurface(yetani, wl_output, wl_surface);
6084  }
6085 
6086  break;
6087  }
6088 
6089  yetani->output_state_map[wl_output] = Yetani::OutputState::Done;
6090 }
6091 
6092 
6096 void Yetani::handlerOutputGeometry(void* data
6097  , struct wl_output* wl_output
6098  , int32_t x
6099  , int32_t y
6100  , int32_t physical_width
6101  , int32_t physical_height
6102  , int32_t subpixel
6103  , const char* make
6104  , const char* model
6105  , int32_t transform
6106  ) noexcept
6107 {
6108  Yetani* yetani = (Yetani*)data;
6109  Yetani::Output& output_changes = yetani->output_changes_map[wl_output];
6110 
6111  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6112  {
6113  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6114  }
6115 
6116  output_changes.x = x;
6117  output_changes.y = y;
6118  output_changes.physical_width_mm = physical_width;
6119  output_changes.physical_height_mm = physical_height;
6120  output_changes.subpixel = subpixel;
6121  output_changes.make = std::string(make);
6122  output_changes.model = std::string(model);
6123  output_changes.transform = transform;
6124 }
6125 
6126 
6130 void Yetani::handlerOutputMode(void* data
6131  , struct wl_output* wl_output
6132  , uint32_t flags
6133  , int32_t width
6134  , int32_t height
6135  , int32_t refresh
6136  ) noexcept
6137 {
6138  Yetani* yetani = (Yetani*)data;
6139  Yetani::Output& output_changes = yetani->output_changes_map[wl_output];
6140 
6141  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6142  {
6143  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6144  }
6145 
6146  output_changes.flags = flags;
6147  output_changes.width = width;
6148  output_changes.height = height;
6149  output_changes.refresh_mHz = refresh;
6150 }
6151 
6152 
6156 void Yetani::handlerOutputScale(void* data
6157  , struct wl_output* wl_output
6158  , int32_t factor
6159  ) noexcept
6160 {
6161  Yetani* yetani = (Yetani*)data;
6162  Output& output_changes = yetani->output_changes_map[wl_output];
6163 
6164  if(yetani->output_state_map[wl_output] != Yetani::OutputState::Added)
6165  {
6166  yetani->output_state_map[wl_output] = Yetani::OutputState::Changed;
6167  }
6168 
6169  output_changes.scale_factor = factor;
6170 }
6171 
6172 // }}}
6173 // {{{ Wayland : Listener Handlers : Pointer
6174 
6178 void Yetani::handlerPointerAxis(void* data
6179  , struct wl_pointer* wl_pointer
6180  , uint32_t time
6181  , uint32_t axis
6182  , wl_fixed_t value
6183  ) noexcept
6184 {
6185  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6186 
6187  pointer.axis.time = time;
6188  pointer.axis.distance = (float)wl_fixed_to_double(value);
6189 
6190  if(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
6191  {
6192  pointer.axis.type = Yetani::PointerAxisType::Horizontal;
6193  }
6194  else if(axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
6195  {
6196  pointer.axis.type = Yetani::PointerAxisType::Vertical;
6197  }
6198  else
6199  {
6200  pointer.axis.type = Yetani::PointerAxisType::Unknown;
6201  }
6202 }
6203 
6204 
6208 void Yetani::handlerPointerAxisDiscrete(void* data
6209  , struct wl_pointer* wl_pointer
6210  , uint32_t axis
6211  , int32_t discrete
6212  ) noexcept
6213 {
6214  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6215 
6216  pointer.axis.steps = discrete;
6217 }
6218 
6219 
6223 void Yetani::handlerPointerAxisSource(void* data
6224  , struct wl_pointer* wl_pointer
6225  , uint32_t axis_source
6226  ) noexcept
6227 {
6228  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6229 
6230  switch(axis_source)
6231  {
6232  case WL_POINTER_AXIS_SOURCE_WHEEL:
6233  pointer.axis.source = Yetani::PointerAxisSource::Wheel;
6234  break;
6235 
6236  case WL_POINTER_AXIS_SOURCE_FINGER:
6237  pointer.axis.source = Yetani::PointerAxisSource::Finger;
6238  break;
6239 
6240  case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
6241  pointer.axis.source = Yetani::PointerAxisSource::Continuous;
6242  break;
6243 
6244  case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
6245  pointer.axis.source = Yetani::PointerAxisSource::Wheel_Tilt;
6246  break;
6247 
6248  default:
6249  pointer.axis.source = Yetani::PointerAxisSource::Unknown;
6250  }
6251 }
6252 
6253 
6257 void Yetani::handlerPointerAxisStop(void*
6258  , struct wl_pointer*
6259  , uint32_t
6260  , uint32_t
6261  ) noexcept
6262 {
6263  // --- Ignored ---
6264  //
6265  // Wayland documentation suggests that the "axis stop" can be used for
6266  // kinetic scrolling or to determine when one axis motions begins anew.
6267  //
6268  // This is not needed.
6269  // - For kinetic scrolling: Have the default scrolling be kinetic and
6270  // treat axis input as a new (or additive) velocity.
6271  // - For separation of axis motion, why? If there is a pause in the
6272  // motion, that reflects the user input.
6273 }
6274 
6275 
6279 void Yetani::handlerPointerButton(void* data
6280  , struct wl_pointer* wl_pointer
6281  , uint32_t serial
6282  , uint32_t time
6283  , uint32_t button
6284  , uint32_t state
6285  ) noexcept
6286 {
6287  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6288 
6289  pointer.button.code = button;
6290  pointer.button_time = time;
6291 
6292  if(state == WL_POINTER_BUTTON_STATE_RELEASED)
6293  {
6294  pointer.button.state = Yetani::PointerButtonState::Released;
6295  }
6296  else if(state == WL_POINTER_BUTTON_STATE_PRESSED)
6297  {
6298  pointer.button.state = Yetani::PointerButtonState::Pressed;
6299  }
6300 }
6301 
6302 
6306 void Yetani::handlerPointerEnter(void* data
6307  , struct wl_pointer* wl_pointer
6308  , uint32_t serial
6309  , struct wl_surface* wl_surface
6310  , wl_fixed_t surface_x
6311  , wl_fixed_t surface_y
6312  ) noexcept
6313 {
6314  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6315 
6316  pointer.enter_serial = serial;
6317  pointer.enter_surface = wl_surface;
6318 
6319  pointer.enter_point =
6320  { .time = 0
6321  , .x = wl_fixed_to_int(surface_x)
6322  , .y = wl_fixed_to_int(surface_y)
6323  };
6324 }
6325 
6326 
6330 void Yetani::handlerPointerFrame(void* data
6331  , struct wl_pointer* wl_pointer
6332  ) noexcept
6333 {
6334  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6335  Yetani* yetani = pointer.yetani;
6336 
6337  if(pointer.enter_surface != nullptr)
6338  {
6339  if(pointer.wl_surface != nullptr)
6340  {
6341  yetani->cursorLeave(pointer.wl_surface);
6342  pointer.event_map[pointer.wl_surface].on_leave();
6343  }
6344 
6345  yetani->cursorEnter(wl_pointer
6346  , pointer.enter_serial
6347  , pointer.enter_surface
6348  );
6349 
6350  pointer.wl_surface = pointer.enter_surface;
6351  pointer.point_pixel = pointer.enter_point;
6352 
6353  if(pointer.event_map.contains(pointer.wl_surface))
6354  {
6355  pointer.event = &(pointer.event_map[pointer.wl_surface]);
6356  }
6357  else
6358  {
6359  pointer.event = &(pointer.event_map[nullptr]);
6360  }
6361 
6362  yetani->convertPixel(pointer.enter_surface
6363  , pointer.point_pixel.x , pointer.point_pixel.y
6364  , pointer.point_mm.x , pointer.point_mm.y
6365  , pointer.point_percent.x, pointer.point_percent.y
6366  );
6367 
6368  pointer.event->on_enter_pixel(pointer.point_pixel
6369  , yetani->keyboard.modifier
6370  );
6371  pointer.event->on_enter_mm(pointer.point_mm
6372  , yetani->keyboard.modifier
6373  );
6374  pointer.event->on_enter_percent(pointer.point_percent
6375  , yetani->keyboard.modifier
6376  );
6377  }
6378 
6379  if((pointer.motion_point.time != 0)
6380  && (pointer.wl_surface != nullptr)
6381  )
6382  {
6383  pointer.point_pixel = pointer.motion_point;
6384 
6385  yetani->convertPixel(pointer.wl_surface
6386  , pointer.point_pixel.x , pointer.point_pixel.y
6387  , pointer.point_mm.x , pointer.point_mm.y
6388  , pointer.point_percent.x, pointer.point_percent.y
6389  );
6390  pointer.point_mm.time = pointer.point_pixel.time;
6391  pointer.point_percent.time = pointer.point_pixel.time;
6392 
6393  pointer.event->on_motion_pixel(pointer.point_pixel
6394  , yetani->keyboard.modifier
6395  );
6396  pointer.event->on_motion_mm(pointer.point_mm
6397  , yetani->keyboard.modifier
6398  );
6399  pointer.event->on_motion_percent(pointer.point_percent
6400  , yetani->keyboard.modifier
6401  );
6402  }
6403 
6404  if((pointer.button_time != 0)
6405  && (pointer.wl_surface != nullptr)
6406  )
6407  {
6408  pointer.point_mm.time = pointer.button_time;
6409  pointer.point_percent.time = pointer.button_time;
6410  pointer.point_pixel.time = pointer.button_time;
6411 
6412  pointer.event->on_button_pixel(pointer.button
6413  , pointer.point_pixel
6414  , yetani->keyboard.modifier
6415  );
6416  pointer.event->on_button_mm(pointer.button
6417  , pointer.point_mm
6418  , yetani->keyboard.modifier
6419  );
6420  pointer.event->on_button_percent(pointer.button
6421  , pointer.point_percent
6422  , yetani->keyboard.modifier
6423  );
6424  }
6425 
6426  if((pointer.axis.time != 0)
6427  && (pointer.wl_surface != nullptr)
6428  )
6429  {
6430  pointer.event->on_axis(pointer.axis
6431  , yetani->keyboard.modifier
6432  );
6433  }
6434 
6435  if((pointer.leave_surface != nullptr)
6436  && (pointer.leave_surface == pointer.wl_surface)
6437  )
6438  {
6439  yetani->cursorLeave(pointer.leave_surface);
6440 
6441  pointer.event->on_leave();
6442 
6443  pointer.event = &(pointer.event_map[nullptr]);
6444  pointer.wl_surface = nullptr;
6445  }
6446 
6447  pointerClear(pointer);
6448 }
6449 
6450 
6454 void Yetani::handlerPointerLeave(void* data
6455  , struct wl_pointer* wl_pointer
6456  , uint32_t serial
6457  , struct wl_surface* wl_surface
6458  ) noexcept
6459 {
6460  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6461 
6462  pointer.leave_surface = wl_surface;
6463 }
6464 
6465 
6469 void Yetani::handlerPointerMotion(void* data
6470  , struct wl_pointer* wl_pointer
6471  , uint32_t time
6472  , wl_fixed_t surface_x
6473  , wl_fixed_t surface_y
6474  ) noexcept
6475 {
6476  Yetani::Pointer& pointer = *((Yetani::Pointer*)data);
6477 
6478  pointer.motion_point =
6479  { .time = time
6480  , .x = wl_fixed_to_int(surface_x)
6481  , .y = wl_fixed_to_int(surface_y)
6482  };
6483 }
6484 
6485 // }}}
6486 // {{{ Wayland : Listener Handlers : Registry
6487 
6491 void Yetani::handlerRegistryGlobal(void* data
6492  , struct wl_registry* registry
6493  , uint32_t id
6494  , const char* interface
6495  , uint32_t version
6496  ) noexcept
6497 {
6498  Yetani* yetani = (Yetani*)data;
6499 
6500  std::string_view interface_name(interface);
6501  ZAKERO_YETANI__DEBUG_VAR(interface_name);
6502 
6503  if(interface_name == wl_compositor_interface.name)
6504  {
6505  yetani->compositor = (struct wl_compositor*)
6506  wl_registry_bind(registry
6507  , id
6508  , &wl_compositor_interface
6509  , 1
6510  );
6511 
6512  return;
6513  }
6514 
6515  if(interface_name == wl_output_interface.name)
6516  {
6517  struct wl_output* wl_output = (struct wl_output*)wl_registry_bind(registry
6518  , id
6519  , &wl_output_interface
6520  , 2
6521  );
6522 
6523  yetani->output_data.wloutput_to_outputid[wl_output] = id;
6524  yetani->output_data.outputid_to_wloutput[id] = wl_output;
6525  yetani->output_data.output_map[wl_output] = {};
6526  yetani->output_changes_map[wl_output] = {};
6527  yetani->output_state_map[wl_output] = Yetani::OutputState::Added;
6528 
6529  wl_output_add_listener(wl_output
6530  , &Yetani::output_listener
6531  , yetani
6532  );
6533 
6534  return;
6535  }
6536 
6537  if(interface_name == wl_seat_interface.name)
6538  {
6539  yetani->seat = (struct wl_seat*)
6540  wl_registry_bind(registry
6541  , id
6542  , &wl_seat_interface
6543  , version
6544  );
6545 
6546  yetani->id_to_seat[id] = yetani->seat;
6547 
6548  wl_seat_add_listener(yetani->seat
6549  , &yetani->seat_listener
6550  , yetani
6551  );
6552 
6553  return;
6554  }
6555 
6556  if(interface_name == wl_shm_interface.name)
6557  {
6558  yetani->shm = (struct wl_shm*)
6559  wl_registry_bind(registry
6560  , id
6561  , &wl_shm_interface
6562  , version
6563  );
6564 
6565  wl_shm_add_listener(yetani->shm
6566  , &yetani->shm_listener
6567  , yetani
6568  );
6569 
6570  return;
6571  }
6572 
6573  if(interface_name == xdg_wm_base_interface.name)
6574  {
6575  yetani->xdg_wm_base = (struct xdg_wm_base*)
6576  wl_registry_bind(registry
6577  , id
6578  , &xdg_wm_base_interface
6579  , 1
6580  );
6581 
6582  xdg_wm_base_add_listener(yetani->xdg_wm_base
6583  , &yetani->xdg_wm_base_listener
6584  , yetani
6585  );
6586  }
6587 
6588  if(interface_name == zxdg_decoration_manager_v1_interface.name)
6589  {
6590  yetani->decoration_manager = (struct zxdg_decoration_manager_v1*)
6591  wl_registry_bind(registry
6592  , id
6593  , &zxdg_decoration_manager_v1_interface
6594  , 1
6595  );
6596  ZAKERO_YETANI__DEBUG << "--- Using UNSTABLE Decoration Manager ---\n";
6597  }
6598 }
6599 
6600 
6604 void Yetani::handlerRegistryRemove(void* data
6605  , struct wl_registry* registry
6606  , uint32_t id
6607  ) noexcept
6608 {
6609  Yetani* yetani = (Yetani*)data;
6610 
6611  printf("Got a registry remove event for id %d\n", id);
6612 
6613  // Output
6614  {
6615  std::lock_guard<std::mutex> lock(yetani->output_data.mutex);
6616 
6617  if(yetani->output_data.outputid_to_wloutput.contains(id))
6618  {
6619  struct wl_output* wl_output = yetani->output_data.outputid_to_wloutput[id];
6620 
6621  yetani->output_data.outputid_to_wloutput.erase(id);
6622  yetani->output_data.wloutput_to_outputid.erase(wl_output);
6623 
6624  yetani->output_changes_map.erase(wl_output);
6625  yetani->output_state_map.erase(wl_output);
6626 
6627  yetani->on_output_remove(id);
6628  yetani->output_data.output_map.erase(wl_output);
6629 
6630  return;
6631  }
6632  }
6633 
6634  // Seat
6635  {
6636  if(yetani->id_to_seat.contains(id))
6637  {
6638  struct wl_seat* wl_seat = yetani->id_to_seat[id];
6639 
6640  yetani->seatDestroy(wl_seat);
6641 
6642  yetani->id_to_seat.erase(id);
6643  }
6644  }
6645 }
6646 
6647 // }}}
6648 // {{{ Wayland : Listener Handlers : Seat
6649 
6657 void Yetani::handlerSeatCapabilities(void* data
6658  , struct wl_seat* wl_seat
6659  , uint32_t capabilities
6660  ) noexcept
6661 {
6662  ZAKERO_YETANI__DEBUG_VAR((uint64_t)wl_seat);
6663 
6664  Yetani* yetani = (Yetani*)data;
6665  Yetani::Seat& seat = yetani->seat_map[wl_seat];
6666 
6667  seat.version = wl_seat_get_version(wl_seat);
6668 
6669  if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD)
6670  {
6671  ZAKERO_YETANI__DEBUG << "-- Got a keyboard device --\n";
6672 
6673  yetani->keyboard.event_map[nullptr] =
6674  { .on_enter = Lambda_DoNothing
6675  , .on_leave = Lambda_DoNothing
6676  , .on_key = LambdaKey_DoNothing
6677  };
6678 
6679  yetani->keyboard.event = &(yetani->keyboard.event_map[nullptr]);
6680 
6681  seat.wl_keyboard = wl_seat_get_keyboard(wl_seat);
6682 
6683  wl_keyboard_add_listener(seat.wl_keyboard
6684  , &Yetani::keyboard_listener
6685  , &yetani->keyboard
6686  );
6687  }
6688 
6689  if(capabilities & WL_SEAT_CAPABILITY_POINTER)
6690  {
6691  ZAKERO_YETANI__DEBUG << "-- Got a pointer device --\n";
6692 
6693  yetani->pointer.yetani = yetani;
6694 
6695  yetani->pointer.event_map[nullptr] =
6696  { .on_axis = LambdaAxis_DoNothing
6697  , .on_axis_discrete = Lambda_DoNothing
6698  , .on_axis_source = Lambda_DoNothing
6699  , .on_axis_stop = Lambda_DoNothing
6700  , .on_button_mm = LambdaButtonMm_DoNothing
6701  , .on_button_percent = LambdaButtonPercent_DoNothing
6702  , .on_button_pixel = LambdaButtonPixel_DoNothing
6703  , .on_enter_mm = LambdaPointMm_DoNothing
6704  , .on_enter_percent = LambdaPointPercent_DoNothing
6705  , .on_enter_pixel = LambdaPointPixel_DoNothing
6706  , .on_leave = Lambda_DoNothing
6707  , .on_motion_mm = LambdaPointMm_DoNothing
6708  , .on_motion_percent = LambdaPointPercent_DoNothing
6709  , .on_motion_pixel = LambdaPointPixel_DoNothing
6710  };
6711 
6712  yetani->pointer.event = &(yetani->pointer.event_map[nullptr]);
6713 
6714  seat.wl_pointer = wl_seat_get_pointer(wl_seat);
6715 
6716  wl_pointer_add_listener(seat.wl_pointer
6717  , &Yetani::pointer_listener
6718  , &yetani->pointer
6719  );
6720  }
6721 
6722  if(capabilities & WL_SEAT_CAPABILITY_TOUCH)
6723  {
6724  ZAKERO_YETANI__DEBUG << "-- Got a touch device --\n";
6725  seat.wl_touch = wl_seat_get_touch(wl_seat);
6726 
6727  //wl_touch_add_listener(seat.wl_touch
6728  // , &Yetani::touch_listener
6729  // , data
6730  // );
6731  }
6732 }
6733 
6734 
6738 void Yetani::handlerSeatName(void* data
6739  , struct wl_seat* wl_seat
6740  , const char* name
6741  ) noexcept
6742 {
6743  ZAKERO_YETANI__DEBUG_VAR((uint64_t)wl_seat);
6744  ZAKERO_YETANI__DEBUG_VAR(name);
6745 
6746  Yetani* yetani = (Yetani*)data;
6747 
6748  yetani->seat_map[wl_seat].name = name;
6749 }
6750 
6751 // }}}
6752 // {{{ Wayland : Listener Handlers : SHM
6753 
6757 void Yetani::handlerShmFormat(void* data
6758  , struct wl_shm* /* Unused */
6759  , uint32_t value
6760  ) noexcept
6761 {
6762  Yetani* yetani = (Yetani*)data;
6763 
6764  wl_shm_format format = (wl_shm_format)value;
6765 
6766  if(vectorContains(yetani->shm_format_vector, format))
6767  {
6768  return;
6769  }
6770 
6771  yetani->shm_format_vector.push_back(format);
6772 }
6773 
6774 // }}}
6775 // {{{ Wayland : Listener Handlers : Surface
6776 
6780 void Yetani::handlerSurfaceEnter(void* data
6781  , struct wl_surface* wl_surface
6782  , struct wl_output* wl_output
6783  ) noexcept
6784 {
6785  //ZAKERO_YETANI__DEBUG << "-------------------------------------------\n";
6786  //ZAKERO_YETANI__DEBUG_VAR(data);
6787  //ZAKERO_YETANI__DEBUG_VAR(wl_surface);
6788  //ZAKERO_YETANI__DEBUG_VAR(wl_output);
6789 
6790  Yetani* yetani = (Yetani*)data;
6791  Yetani::OutputData& output_data = yetani->output_data;
6792 
6793  output_data.mutex.lock();
6794  output_data.surface_output_map[wl_surface].push_back(wl_output);
6795  output_data.mutex.unlock();
6796 }
6797 
6798 
6802 void Yetani::handlerSurfaceLeave(void* data
6803  , struct wl_surface* wl_surface
6804  , struct wl_output* wl_output
6805  ) noexcept
6806 {
6807  //ZAKERO_YETANI__DEBUG << "-------------------------------------------\n";
6808  //ZAKERO_YETANI__DEBUG_VAR(data);
6809  //ZAKERO_YETANI__DEBUG_VAR(wl_surface);
6810  //ZAKERO_YETANI__DEBUG_VAR(wl_output);
6811 
6812  Yetani* yetani = (Yetani*)data;
6813 
6814  Yetani::OutputData& output_data = yetani->output_data;
6815  std::lock_guard<std::mutex> lock(output_data.mutex);
6816 
6817  Yetani::VectorWlOutput& output_vector = output_data.surface_output_map[wl_surface];
6818 
6819  // Save the current wl_output device id
6820  struct wl_output* current_output = output_vector.front();
6821 
6822  // Remove the wl_output device id
6823  zakero::vectorErase(output_vector, wl_output);
6824 
6825  // Check if the current wl_output device id was removed
6826  if(current_output == output_vector.front())
6827  {
6828  // Current wl_output device was not removed
6829  // so nothing to do.
6830 
6831  return;
6832  }
6833 
6834  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
6835 
6836  if(surface_extent.preferred_unit == Yetani::SizeUnit::Pixel)
6837  {
6838  return;
6839  }
6840 
6841  // Convert the relative window size from the old wl_output device
6842  // to the new wl_output device.
6843 
6844  current_output = output_vector.front();
6845 
6846  Yetani::Output& output = output_data.output_map.at(current_output);
6847  Yetani::SizePixel new_size;
6848 
6849  if(surface_extent.preferred_unit == Yetani::SizeUnit::Millimeter)
6850  {
6851  auto p = yetani->convertMmToPixel(output
6852  , surface_extent.size_mm.width
6853  , surface_extent.size_mm.height
6854  );
6855 
6856  new_size = { p.first, p.second };
6857  }
6858  else // if(surface_extent.preferred_unit == Yetani::SizeUnit::Percent)
6859  {
6860  auto p = yetani->convertPercentToPixel(output
6861  , surface_extent.size_percent.width
6862  , surface_extent.size_percent.height
6863  );
6864 
6865  new_size = { p.first, p.second };
6866  }
6867 
6868  if(new_size.width <= 0)
6869  {
6870  new_size.width = 1;
6871  }
6872 
6873  if(new_size.height <= 0)
6874  {
6875  new_size.height = 1;
6876  }
6877 
6878  if((new_size.width != surface_extent.size_pixel.width)
6879  && (new_size.height != surface_extent.size_pixel.height)
6880  )
6881  {
6882  yetani->surface_resize_mutex_map[wl_surface].lock();
6883  {
6884  XdgSurface& surface = yetani->xdg_surface_map[wl_surface];
6885 
6886  surface_extent.size_pixel = new_size;
6887  surfaceCalculateSize(surface.yetani, surface.wl_surface, new_size);
6888  }
6889  yetani->surface_resize_mutex_map[wl_surface].unlock();
6890 
6891  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
6892  event.on_size_pixel_change(surface_extent.size_pixel);
6893  }
6894 }
6895 
6896 // }}}
6897 // {{{ Wayland : Listener Handlers : SwapBuffers
6898 
6902 void Yetani::handlerSwapBuffers(void* data
6903  , struct wl_callback* callback
6904  , uint32_t time_ms
6905  ) noexcept
6906 {
6907  Yetani::SurfaceFrame* surface_frame = (Yetani::SurfaceFrame*)data;
6908 
6909  wl_callback_destroy(callback);
6910 
6911  surface_frame->callback = wl_surface_frame(surface_frame->wl_surface);
6912 
6913  wl_callback_add_listener(surface_frame->callback
6914  , &frame_callback_listener
6915  , data
6916  );
6917 
6918  struct wl_buffer* wl_buffer = surface_frame->buffer_next.exchange(nullptr);
6919  if(wl_buffer != nullptr)
6920  {
6921  surface_frame->time_ms = time_ms;
6922 
6923  wl_surface_attach(surface_frame->wl_surface, wl_buffer, 0, 0);
6924 
6925  wl_surface_damage(surface_frame->wl_surface
6926  , 0, 0
6927  , surface_frame->width, surface_frame->height
6928  );
6929  }
6930 
6931  wl_surface_commit(surface_frame->wl_surface);
6932 }
6933 
6934 // }}}
6935 // {{{ Wayland : Listener Handlers (Unstable)
6936 
6937 
6938 // }}}
6939 // {{{ XDG
6940 
6953 Yetani::WindowMode Yetani::toWindowMode(const Yetani::XdgState state
6954  ) noexcept
6955 {
6956  switch(state)
6957  {
6958  case Yetani::XdgState::Toplevel_Window_Fullscreen:
6960 
6961  case Yetani::XdgState::Toplevel_Window_Maximized:
6963 
6964  default:
6965  case Yetani::XdgState::Toplevel_Window_Normal:
6967  }
6968 }
6969 
6970 
6976 Yetani::XdgState Yetani::toXdgState(const Yetani::WindowMode window_mode
6977  ) noexcept
6978 {
6979  switch(window_mode)
6980  {
6982  return Yetani::XdgState::Toplevel_Window_Fullscreen;
6983 
6985  return Yetani::XdgState::Toplevel_Window_Maximized;
6986 
6987  default:
6989  return Yetani::XdgState::Toplevel_Window_Normal;
6990  }
6991 }
6992 
6993 // }}}
6994 // {{{ XDG : Surface
6995 
7016 struct xdg_surface* Yetani::xdgSurfaceCreate(struct wl_surface* wl_surface
7017  ) noexcept
7018 {
7019  XdgSurface& surface = xdg_surface_map[wl_surface];
7020 
7021  surface.yetani = this;
7022  surface.wl_surface = wl_surface;
7023 
7024  surface_extent_mutex.lock();
7025  {
7026  Yetani::SurfaceExtent& surface_extent = surface_extent_map[wl_surface];
7027 
7028  surface_extent.preferred_unit = Yetani::SizeUnit::Pixel;
7029  surface_extent.preferred_mm = { 160, 90 }; // 16:9 * 10mm
7030  surface_extent.preferred_percent = { 0.32, 0.18 }; // 16:9 * 0.02
7031  surface_extent.size_mm = { 160, 90 }; // 16:9 + 10mm
7032  surface_extent.size_percent = { 0.32, 0.18 }; // 16:9 * 0.02
7033  surface_extent.size_pixel = { 800, 450 }; // 16:9 * 50 pixels
7034  surface_extent.size_pixel_max = { 0, 0 }; // No maximum size
7035  surface_extent.size_pixel_min = { 0, 0 }; // No minimum size
7036  }
7037  surface_extent_mutex.unlock();
7038 
7039  output_notify_surface_vector.push_back(wl_surface);
7040 
7041  struct xdg_surface* xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base
7042  , wl_surface
7043  );
7044 
7045  xdg_state_change_mutex.lock();
7046  {
7047  xdg_state_change_map[xdg_surface] = {};
7048  }
7049  xdg_state_change_mutex.unlock();
7050 
7051  xdg_surface_add_listener(xdg_surface
7052  , &xdg_surface_listener
7053  , &surface
7054  );
7055 
7056  return xdg_surface;
7057 }
7058 
7059 
7068 void Yetani::xdgSurfaceDestroy(struct wl_surface* wl_surface
7069  , struct xdg_surface*& xdg_surface
7070  ) noexcept
7071 {
7072  if(xdg_surface)
7073  {
7074  xdg_surface_destroy(xdg_surface);
7075  }
7076 
7077  zakero::vectorErase(output_notify_surface_vector, wl_surface);
7078 
7079  if(xdg_surface_map.contains(wl_surface))
7080  {
7081  xdg_surface_map.erase(wl_surface);
7082  }
7083 
7084  xdg_state_change_mutex.lock();
7085  {
7086  if(xdg_state_change_map.contains(xdg_surface))
7087  {
7088  xdg_state_change_map.erase(xdg_surface);
7089  }
7090  }
7091  xdg_state_change_mutex.unlock();
7092 
7093  surface_extent_mutex.lock();
7094  {
7095  if(surface_extent_map.contains(wl_surface))
7096  {
7097  surface_extent_map.erase(wl_surface);
7098  }
7099  }
7100  surface_extent_mutex.unlock();
7101 
7102  xdg_surface = nullptr;
7103 }
7104 
7105 
7109 void Yetani::xdgSurfaceSetExtent(struct wl_surface* wl_surface
7110  , const Yetani::SizeUnit& size_unit
7111  , const Yetani::SizeMm& size_mm
7112  , const Yetani::SizePercent& size_percent
7113  , const Yetani::SizePixel& size_pixel
7114  ) noexcept
7115 {
7116  Yetani::SurfaceExtent& surface_extent = surface_extent_map[wl_surface];
7117 
7118  surface_extent.preferred_unit = size_unit;
7119  surface_extent.preferred_mm = size_mm;
7120  surface_extent.preferred_percent = size_percent;
7121  surface_extent.size_mm = size_mm;
7122  surface_extent.size_percent = size_percent;
7123  surface_extent.size_pixel = size_pixel;
7124  surface_extent.size_pixel_max = { 0, 0 };
7125  surface_extent.size_pixel_min = { 0, 0 };
7126 }
7127 
7128 // }}}
7129 // {{{ XDG : Toplevel
7130 
7169 struct xdg_toplevel* Yetani::xdgToplevelCreate(struct xdg_surface* xdg_surface
7170  ) noexcept
7171 {
7172  Yetani::XdgToplevel& toplevel = xdg_toplevel_map[xdg_surface];
7173 
7174  toplevel.close_request_lambda = Lambda_DoNothing;
7175  toplevel.state_change = &(xdg_state_change_map[xdg_surface]);
7176  toplevel.is_active = false;
7177  toplevel.window_state = Yetani::XdgState::Toplevel_Window_Normal;
7178  toplevel.is_active_lambda = LambdaBool_DoNothing;
7179  toplevel.window_state_lambda = LambdaWindowMode_DoNothing;
7180  toplevel.previous_size = { 0, 0 };
7181  toplevel.xdg_toplevel = nullptr;
7182 
7188  toplevel.state_change->push_back(Yetani::XdgState::Toplevel_Attach_Buffer);
7189 
7190  struct xdg_toplevel* xdg_toplevel = nullptr;
7191 
7192  xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
7193  toplevel.xdg_toplevel = xdg_toplevel;
7194 
7195  xdg_toplevel_add_listener(xdg_toplevel
7196  , &xdg_toplevel_listener
7197  , &toplevel
7198  );
7199 
7200  return xdg_toplevel;
7201 }
7202 
7203 
7210 void Yetani::xdgToplevelDestroy(struct xdg_surface* xdg_surface
7211  , struct xdg_toplevel*& xdg_toplevel
7212  ) noexcept
7213 {
7214  if(xdg_toplevel != nullptr)
7215  {
7216  xdg_toplevel_destroy(xdg_toplevel);
7217  }
7218 
7219  if(xdg_toplevel_map.contains(xdg_surface))
7220  {
7221  XdgToplevel& toplevel = xdg_toplevel_map[xdg_surface];
7222 
7223  toplevel.close_request_lambda = nullptr;
7224  toplevel.state_change = nullptr;
7225  toplevel.window_state = Yetani::XdgState::Unknown;
7226  toplevel.is_active = false;
7227  toplevel.is_active_lambda = nullptr;
7228  toplevel.window_state_lambda = nullptr;
7229 
7230  xdg_toplevel_map.erase(xdg_surface);
7231  }
7232 
7233  xdg_toplevel = nullptr;
7234 }
7235 
7236 
7246 void Yetani::xdgToplevelSizeChange(Yetani* yetani
7247  , struct wl_surface* wl_surface
7248  , const Yetani::SizePixel& size_pixel
7249  ) noexcept
7250 {
7251  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7252  Yetani::SizePixel new_size = surface_extent.size_pixel;
7253 
7254  if(((surface_extent.size_pixel_min.width == 0) || (size_pixel.width >= surface_extent.size_pixel_min.width))
7255  && ((surface_extent.size_pixel_max.width == 0) || (size_pixel.width <= surface_extent.size_pixel_max.width))
7256  )
7257  {
7258  new_size.width = size_pixel.width;
7259  }
7260 
7261  if(((surface_extent.size_pixel_min.height == 0) || (size_pixel.height >= surface_extent.size_pixel_min.height))
7262  && ((surface_extent.size_pixel_max.height == 0) || (size_pixel.height <= surface_extent.size_pixel_max.height))
7263  )
7264  {
7265  new_size.height = size_pixel.height;
7266  }
7267 
7268  if((new_size.width == surface_extent.size_pixel.width)
7269  && (new_size.height == surface_extent.size_pixel.height)
7270  )
7271  {
7272  return;
7273  }
7274 
7275  // Calculate Sizes
7276  Yetani::SizeMm size_mm;
7277  Yetani::SizePercent size_percent;
7278  yetani->convertPixel(wl_surface
7279  , size_pixel.width , size_pixel.height
7280  , size_mm.width , size_mm.height
7281  , size_percent.width, size_percent.height
7282  );
7283 
7284  yetani->surface_resize_mutex_map[wl_surface].lock();
7285  {
7286  surface_extent.size_pixel = new_size;
7287  surfaceCalculateSize(yetani, wl_surface, new_size);
7288  }
7289  yetani->surface_resize_mutex_map[wl_surface].unlock();
7290 
7291  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
7292  event.on_size_pixel_change(surface_extent.size_pixel);
7293  event.on_size_mm_change(surface_extent.size_mm);
7294  event.on_size_percent_change(surface_extent.size_percent);
7295 }
7296 
7297 
7301 void Yetani::xdgToplevelSizeMinMaxChange(Yetani* yetani
7302  , struct xdg_toplevel* xdg_toplevel
7303  , struct wl_surface* wl_surface
7304  , const Yetani::SizePixel& size_pixel_min
7305  , const Yetani::SizePixel& size_pixel_max
7306  ) noexcept
7307 {
7308  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7309 
7310  Yetani::SizePixel size_pixel = surface_extent.size_pixel;
7311  bool need_to_resize = false;
7312 
7313  if(size_pixel_max.width > 0
7314  && size_pixel_max.width < surface_extent.size_pixel.width
7315  )
7316  {
7317  need_to_resize = true;
7318  size_pixel.width = size_pixel_max.width;
7319  }
7320 
7321  if(size_pixel_max.height > 0
7322  && size_pixel_max.height < surface_extent.size_pixel.height
7323  )
7324  {
7325  need_to_resize = true;
7326  size_pixel.height = size_pixel_max.height;
7327  }
7328 
7329  if(size_pixel_min.width > 0
7330  && size_pixel_min.width > surface_extent.size_pixel.width
7331  )
7332  {
7333  need_to_resize = true;
7334  size_pixel.width = size_pixel_min.width;
7335  }
7336 
7337  if(size_pixel_min.height > 0
7338  && size_pixel_min.height > surface_extent.size_pixel.height
7339  )
7340  {
7341  need_to_resize = true;
7342  size_pixel.height = size_pixel_min.height;
7343  }
7344 
7345  if(need_to_resize)
7346  {
7347  xdg_toplevel_set_max_size(xdg_toplevel, 0, 0);
7348  xdg_toplevel_set_min_size(xdg_toplevel, 0, 0);
7349 
7350  yetani->surface_resize_mutex_map[wl_surface].lock();
7351  {
7352  surface_extent.size_pixel = size_pixel;
7353  surfaceCalculateSize(yetani, wl_surface, size_pixel);
7354  }
7355  yetani->surface_resize_mutex_map[wl_surface].unlock();
7356  }
7357 
7358  xdg_toplevel_set_min_size(xdg_toplevel
7359  , size_pixel_min.width
7360  , size_pixel_min.height
7361  );
7362 
7363  xdg_toplevel_set_max_size(xdg_toplevel
7364  , size_pixel_max.width
7365  , size_pixel_max.height
7366  );
7367 
7368  surface_extent.size_pixel_min = size_pixel_min;
7369  surface_extent.size_pixel_max = size_pixel_max;
7370 }
7371 
7372 
7376 void Yetani::xdgToplevelWindowChange(Yetani* yetani
7377  , struct wl_surface* wl_surface
7378  , Yetani::XdgToplevel& toplevel
7379  , const Yetani::XdgState window_state
7380  , const Yetani::SizePixel& size_pixel
7381  ) noexcept
7382 {
7383  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
7384  Yetani::SizePixel new_size(1, 1);
7385 
7386  toplevel.window_state = window_state;
7387 
7388  if((toplevel.window_state == Yetani::XdgState::Toplevel_Window_Fullscreen)
7389  || (toplevel.window_state == Yetani::XdgState::Toplevel_Window_Maximized)
7390  )
7391  {
7392  if(toplevel.previous_size.width == 0)
7393  {
7394  xdg_toplevel_set_max_size(toplevel.xdg_toplevel, 0, 0);
7395  xdg_toplevel_set_min_size(toplevel.xdg_toplevel, 0, 0);
7396 
7397  toplevel.previous_size = surface_extent.size_pixel;
7398  }
7399 
7400  if((size_pixel.width != 0)
7401  && (size_pixel.height != 0)
7402  )
7403  {
7404  new_size = size_pixel;
7405  }
7406  }
7407  else if(toplevel.window_state == Yetani::XdgState::Toplevel_Window_Normal)
7408  {
7409  xdg_toplevel_set_max_size(toplevel.xdg_toplevel
7410  , surface_extent.size_pixel_max.width
7411  , surface_extent.size_pixel_max.height
7412  );
7413 
7414  xdg_toplevel_set_min_size(toplevel.xdg_toplevel
7415  , surface_extent.size_pixel_min.width
7416  , surface_extent.size_pixel_min.height
7417  );
7418 
7419  new_size = toplevel.previous_size;
7420  toplevel.previous_size.width = 0;
7421  }
7422 
7423  if(new_size == surface_extent.size_pixel)
7424  {
7425  return;
7426  }
7427 
7428  // Calculate Size
7429  Yetani::SizeMm size_mm;
7430  Yetani::SizePercent size_percent;
7431  yetani->convertPixel(wl_surface
7432  , size_pixel.width , size_pixel.height
7433  , size_mm.width , size_mm.height
7434  , size_percent.width, size_percent.height
7435  );
7436 
7437  yetani->surface_resize_mutex_map[wl_surface].lock();
7438  {
7439  surface_extent.size_mm = size_mm;
7440  surface_extent.size_percent = size_percent;
7441  surface_extent.size_pixel = new_size;
7442  surfaceCalculateSize(yetani, wl_surface, new_size);
7443  }
7444  yetani->surface_resize_mutex_map[wl_surface].unlock();
7445 
7446  toplevel.window_state_lambda(Yetani::toWindowMode(toplevel.window_state));
7447 
7448  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
7449  event.on_size_pixel_change(surface_extent.size_pixel);
7450  event.on_size_mm_change(surface_extent.size_mm);
7451  event.on_size_percent_change(surface_extent.size_percent);
7452 }
7453 
7454 // }}}
7455 // {{{ XDG : Decoration (Unstable)
7456 
7480 struct zxdg_toplevel_decoration_v1* Yetani::xdgDecorationCreate(struct xdg_surface* xdg_surface
7481  , struct xdg_toplevel* xdg_toplevel
7482  ) noexcept
7483 {
7484  if(decoration_manager == nullptr)
7485  {
7486  return nullptr;
7487  }
7488 
7489  /* *** From the xdg-decoration-unstable-v1 documentation ***
7490  *
7491  * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
7492  * buffer attached or committed is a client error.
7493  */
7494 
7495  zxdg_toplevel_decoration_v1* xdg_decoration =
7496  zxdg_decoration_manager_v1_get_toplevel_decoration(decoration_manager
7497  , xdg_toplevel
7498  );
7499 
7500  Yetani::XdgDecoration& decoration = xdg_decoration_map[xdg_surface];
7501  decoration.state_change = &(xdg_state_change_map[xdg_surface]);
7502  decoration.lambda = LambdaWindowDecorations_DoNothing;
7503  decoration.state = 0;
7504  decoration.is_present = false;
7505 
7506  zxdg_toplevel_decoration_v1_add_listener(xdg_decoration
7507  , &xdg_toplevel_decoration_listener
7508  , &decoration
7509  );
7510 
7511  return xdg_decoration;
7512 }
7513 
7514 
7520 void Yetani::xdgDecorationDestroy(struct xdg_surface* xdg_surface
7521  , struct xdg_toplevel* xdg_toplevel
7522  , struct zxdg_toplevel_decoration_v1*& xdg_decoration
7523  ) noexcept
7524 {
7525  zxdg_toplevel_decoration_v1_destroy(xdg_decoration);
7526 
7527  if(xdg_decoration_map.contains(xdg_surface))
7528  {
7529  Yetani::XdgDecoration& decoration = xdg_decoration_map[xdg_surface];
7530  decoration.state_change = nullptr;
7531  decoration.lambda = nullptr;
7532  decoration.state = 0;
7533  decoration.is_present = false;
7534 
7535  xdg_decoration_map.erase(xdg_surface);
7536  }
7537 
7538  xdg_decoration = nullptr;
7539 }
7540 
7541 
7547 void Yetani::xdgDecorationChange(Yetani::XdgDecoration& decoration
7548  , const uint32_t decoration_state
7549  ) noexcept
7550 {
7551  if(decoration_state == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)
7552  {
7553  if(decoration.state != decoration_state)
7554  {
7555  decoration.state = decoration_state;
7556  decoration.is_present = false;
7557 
7558  decoration.lambda(
7560  );
7561  }
7562  }
7563  else if(decoration_state == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
7564  {
7565  if(decoration.state != decoration_state)
7566  {
7567  decoration.state = decoration_state;
7568  decoration.is_present = true;
7569  }
7570  else
7571  {
7572  decoration.is_present = !decoration.is_present;
7573  }
7574 
7575  if(decoration.is_present == true)
7576  {
7577  decoration.lambda(
7579  );
7580  }
7581  else
7582  {
7583  decoration.lambda(
7585  );
7586  }
7587  }
7588 }
7589 
7590 // }}}
7591 // {{{ XDG : Listener Handlers : Surface
7592 
7606 void Yetani::handlerXdgSurfaceConfigure(void* data
7607  , xdg_surface* xdg_surface
7608  , uint32_t serial
7609  ) noexcept
7610 {
7611  Yetani::XdgSurface& surface = *((Yetani::XdgSurface*)data);
7612  Yetani* yetani = surface.yetani;
7613 
7614  xdg_surface_ack_configure(xdg_surface, serial);
7615 
7616  VectorXdgStateChange& state_change = yetani->xdg_state_change_map[xdg_surface];
7617 
7618  if(state_change.empty())
7619  {
7620  return;
7621  }
7622 
7623  auto iter = std::begin(state_change);
7624  auto iter_end = std::end(state_change);
7625 
7626  while(iter != iter_end)
7627  {
7628  switch(*iter)
7629  {
7630  case Yetani::XdgState::Toplevel_Active:
7631  {
7632  Yetani::XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
7633 
7634  iter++;
7635  bool is_active = bool(*iter);
7636  if(toplevel.is_active != is_active)
7637  {
7638  toplevel.is_active = is_active;
7639 
7640  toplevel.is_active_lambda(is_active);
7641  }
7642  } break;
7643 
7644  case Yetani::XdgState::Toplevel_Attach_Buffer:
7645  {
7646  struct wl_surface* wl_surface = surface.wl_surface;
7647 
7648  SurfaceFrame& surface_frame =
7649  yetani->surface_frame_map[wl_surface];
7650 
7651  wl_surface_attach(surface_frame.wl_surface
7652  , surface_frame.buffer_next
7653  , 0, 0
7654  );
7655 
7656  surface_frame.callback = wl_surface_frame(surface_frame.wl_surface);
7657 
7658  wl_callback_add_listener(surface_frame.callback
7659  , &frame_callback_listener
7660  , &surface_frame
7661  );
7662 
7663  wl_surface_commit(surface_frame.wl_surface);
7664  } break;
7665 
7666  case Yetani::XdgState::Toplevel_Window_Normal:
7667  case Yetani::XdgState::Toplevel_Window_Maximized:
7668  case Yetani::XdgState::Toplevel_Window_Fullscreen:
7669  {
7670  struct wl_surface* wl_surface = surface.wl_surface;
7671 
7672  Yetani::XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
7673 
7674  Yetani::XdgState window_state = XdgState(*iter);
7675 
7676  Yetani::SizePixel size_pixel;
7677 
7678  iter++;
7679  size_pixel.width = *iter;
7680 
7681  iter++;
7682  size_pixel.height = *iter;
7683 
7684  if(toplevel.window_state != window_state)
7685  {
7686  xdgToplevelWindowChange(yetani
7687  , wl_surface
7688  , toplevel
7689  , window_state
7690  , size_pixel
7691  );
7692  }
7693  } break;
7694 
7695  case Yetani::XdgState::Toplevel_Resizing:
7696  {
7697  struct wl_surface* wl_surface = surface.wl_surface;
7698 
7699  Yetani::SizePixel size_pixel;
7700 
7701  iter++;
7702  size_pixel.width = *iter;
7703 
7704  iter++;
7705  size_pixel.height = *iter;
7706 
7707  if(size_pixel.width > 0
7708  && size_pixel.height > 0
7709  )
7710  {
7711  xdgToplevelSizeChange(yetani
7712  , wl_surface
7713  , size_pixel
7714  );
7715  }
7716  } break;
7717 
7718  case Yetani::XdgState::Toplevel_Decoration:
7719  {
7720  iter++;
7721  uint32_t decoration_state = *iter;
7722 
7723  Yetani::XdgDecoration& decoration = yetani->xdg_decoration_map[xdg_surface];
7724 
7725  xdgDecorationChange(decoration, decoration_state);
7726  } break;
7727  }
7728 
7729  iter++;
7730  }
7731 
7732  state_change.clear();
7733 }
7734 
7735 // }}}
7736 // {{{ XDG : Listener Handlers : Toplevel
7737 
7741 void Yetani::handlerXdgToplevelClose(void* data
7742  , struct xdg_toplevel* xdg_toplevel
7743  ) noexcept
7744 {
7745  Yetani::XdgToplevel* toplevel = (Yetani::XdgToplevel*)data;
7746 
7747  toplevel->close_request_lambda();
7748 }
7749 
7750 
7754 void Yetani::handlerXdgToplevelConfigure(void* data
7755  , struct xdg_toplevel* xdg_toplevel
7756  , int32_t width
7757  , int32_t height
7758  , struct wl_array* state_array
7759  ) noexcept
7760 {
7761  Yetani::XdgToplevel* toplevel = (Yetani::XdgToplevel*)data;
7762 
7763  Yetani::XdgState window_state = Yetani::XdgState::Toplevel_Window_Normal;
7764  int32_t is_active = 0;
7765 
7766  ZAKERO_YETANI__ARRAY_FOR_EACH(xdg_toplevel_state*, state_iter, state_array)
7767  {
7768  xdg_toplevel_state state = *state_iter;
7769 
7770  switch(state)
7771  {
7772  case XDG_TOPLEVEL_STATE_MAXIMIZED:
7773  window_state = Yetani::XdgState::Toplevel_Window_Maximized;
7774  break;
7775  case XDG_TOPLEVEL_STATE_FULLSCREEN:
7776  window_state = Yetani::XdgState::Toplevel_Window_Fullscreen;
7777  break;
7778  case XDG_TOPLEVEL_STATE_RESIZING:
7779  toplevel->state_change->push_back(Yetani::XdgState::Toplevel_Resizing);
7780  toplevel->state_change->push_back(width);
7781  toplevel->state_change->push_back(height);
7782  break;
7783  case XDG_TOPLEVEL_STATE_ACTIVATED:
7784  is_active = 1;
7785  break;
7786  case XDG_TOPLEVEL_STATE_TILED_LEFT:
7787  break;
7788  case XDG_TOPLEVEL_STATE_TILED_RIGHT:
7789  break;
7790  case XDG_TOPLEVEL_STATE_TILED_TOP:
7791  break;
7792  case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
7793  break;
7794  default:
7795  break;
7796  }
7797  }
7798 
7799  toplevel->state_change->push_back(window_state);
7800  toplevel->state_change->push_back(width);
7801  toplevel->state_change->push_back(height);
7802 
7803  toplevel->state_change->push_back(Yetani::XdgState::Toplevel_Active);
7804  toplevel->state_change->push_back(is_active);
7805 }
7806 
7807 // }}}
7808 // {{{ XDG : Listener Handlers : WM Base
7809 
7813 void Yetani::handlerXdgWmBasePing(void* data
7814  , struct xdg_wm_base* xdg_wm_base
7815  , uint32_t serial
7816  ) noexcept
7817 {
7818  xdg_wm_base_pong(xdg_wm_base, serial);
7819 }
7820 
7821 // }}}
7822 // {{{ XDG : Listener Handlers (Unstable) : Decoration
7823 
7827 void Yetani::handlerXdgToplevelDecorationConfigure(void* data
7828  , struct zxdg_toplevel_decoration_v1* decoration
7829  , uint32_t mode
7830  ) noexcept
7831 {
7832  Yetani::XdgDecoration* deco = (Yetani::XdgDecoration*)data;
7833 
7834  deco->state_change->push_back(Yetani::XdgState::Toplevel_Decoration);
7835  deco->state_change->push_back(mode);
7836 }
7837 
7838 // }}}
7839 // {{{ Window
7840 
8002  , std::error_code& error
8003  ) noexcept
8004 {
8005  return windowCreate(Yetani::SizeUnit::Millimeter
8006  , size
8007  , { 0, 0 }
8008  , { 0, 0 }
8009  , SHM_FORMAT_DEFAULT
8010  , error
8011  );
8012 }
8013 
8014 
8028  , const wl_shm_format format
8029  ) noexcept
8030 {
8031  std::error_code error;
8032 
8033  return windowCreate(Yetani::SizeUnit::Millimeter
8034  , size
8035  , { 0, 0 }
8036  , { 0, 0 }
8037  , format
8038  , error
8039  );
8040 }
8041 
8042 
8059  , const wl_shm_format format
8060  , std::error_code& error
8061  ) noexcept
8062 {
8063  return windowCreate(Yetani::SizeUnit::Millimeter
8064  , size
8065  , { 0, 0 }
8066  , { 0, 0 }
8067  , format
8068  , error
8069  );
8070 }
8071 
8072 
8087  , std::error_code& error
8088  ) noexcept
8089 {
8090  return windowCreate(Yetani::SizeUnit::Percent
8091  , { 0, 0 }
8092  , size
8093  , { 0, 0 }
8094  , SHM_FORMAT_DEFAULT
8095  , error
8096  );
8097 }
8098 
8099 
8113  , const wl_shm_format format
8114  ) noexcept
8115 {
8116  std::error_code error;
8117 
8118  return windowCreate(Yetani::SizeUnit::Percent
8119  , { 0, 0 }
8120  , size
8121  , { 0, 0 }
8122  , format
8123  , error
8124  );
8125 }
8126 
8127 
8144  , const wl_shm_format format
8145  , std::error_code& error
8146  ) noexcept
8147 {
8148  return windowCreate(Yetani::SizeUnit::Percent
8149  , { 0, 0 }
8150  , size
8151  , { 0, 0 }
8152  , format
8153  , error
8154  );
8155 }
8156 
8157 
8172  , std::error_code& error
8173  ) noexcept
8174 {
8175  return windowCreate(Yetani::SizeUnit::Pixel
8176  , { 0, 0 }
8177  , { 0, 0 }
8178  , size
8179  , SHM_FORMAT_DEFAULT
8180  , error
8181  );
8182 }
8183 
8184 
8198  , const wl_shm_format format
8199  ) noexcept
8200 {
8201  std::error_code error;
8202 
8203  return windowCreate(Yetani::SizeUnit::Pixel
8204  , { 0, 0 }
8205  , { 0, 0 }
8206  , size
8207  , format
8208  , error
8209  );
8210 }
8211 
8212 
8229  , const wl_shm_format format
8230  , std::error_code& error
8231  ) noexcept
8232 {
8233  return windowCreate(Yetani::SizeUnit::Pixel
8234  , { 0, 0 }
8235  , { 0, 0 }
8236  , size
8237  , format
8238  , error
8239  );
8240 }
8241 
8242 
8250 Yetani::Window* Yetani::windowCreate(const Yetani::SizeUnit size_unit
8251  , const Yetani::SizeMm& size_mm
8252  , const Yetani::SizePercent& size_percent
8253  , const Yetani::SizePixel& size_pixel
8254  , const wl_shm_format pixel_format
8255  , std::error_code& error
8256  ) noexcept
8257 {
8258  if((size_unit == Yetani::SizeUnit::Millimeter)
8259  && (size_mm.width <= 0 || size_mm.height <= 0)
8260  )
8261  {
8262  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8263 
8264  return nullptr;
8265  }
8266 
8267  if((size_unit == Yetani::SizeUnit::Percent)
8268  && (size_percent.width <= 0 || size_percent.height <= 0)
8269  )
8270  {
8271  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8272 
8273  return nullptr;
8274  }
8275 
8276  if((size_unit == Yetani::SizeUnit::Pixel)
8277  && (size_pixel.width <= 0 || size_pixel.height <= 0)
8278  )
8279  {
8280  error = ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
8281 
8282  return nullptr;
8283  }
8284 
8285  const std::string file_name = "Zakero.Yetani."
8286  + std::to_string(ZAKERO_STEADY_TIME_NOW(nanoseconds))
8287  ;
8288 
8289  struct WindowData window_data =
8290  { .yetani = this
8291  , .wl_shm = shm
8292  , .wl_output = nullptr
8293  , .file_name = file_name
8294  , .size_mm = size_mm
8295  , .size_percent = size_percent
8296  , .size_pixel = size_pixel
8297  , .size_unit = size_unit
8298  , .pixel_format = pixel_format
8299  , .error = ZAKERO_YETANI__ERROR(Error_None)
8300  };
8301 
8302  windowDataInit(window_data);
8303 
8304  if(window_data.error)
8305  {
8306  error = window_data.error;
8307 
8308  return nullptr;
8309  }
8310 
8311  Yetani::Window* window = new Window(&window_data);
8312 
8313  if(window_data.error)
8314  {
8315  delete window;
8316  window = nullptr;
8317 
8318  ZAKERO_YETANI__DEBUG << to_string(window_data.error) << "\n";
8319 
8320  error = ZAKERO_YETANI__ERROR(Error_Window_Initialization_Failed);
8321 
8322  return nullptr;
8323  }
8324 
8325  error = ZAKERO_YETANI__ERROR(Error_None);
8326 
8327  return window;
8328 }
8329 
8330 
8334 void Yetani::windowDataInit(Yetani::WindowData& window_data
8335  ) noexcept
8336 {
8337  windowDataInitOutput(window_data);
8338 
8339  if(window_data.error)
8340  {
8341  return;
8342  }
8343 
8344  window_data.size_pixel.width = std::max(1, window_data.size_pixel.width);
8345  window_data.size_pixel.height = std::max(1, window_data.size_pixel.height);
8346 
8347  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8348 }
8349 
8350 
8354 void Yetani::windowDataInitOutput(Yetani::WindowData& window_data
8355  ) noexcept
8356 {
8357  std::lock_guard<std::mutex> lock(output_data.mutex);
8358 
8359  if(output_data.output_map.empty())
8360  {
8361  window_data.error = ZAKERO_YETANI__ERROR(Error_No_Output_Available);
8362 
8363  return;
8364  }
8365 
8366  const auto& iter = output_data.output_map.begin();
8367 
8368  window_data.wl_output = iter->first;
8369  Yetani::Output& output = iter->second;
8370 
8371  if(window_data.size_unit == Yetani::SizeUnit::Millimeter)
8372  {
8373  auto px = convertMmToPixel(output
8374  , window_data.size_mm.width
8375  , window_data.size_mm.height
8376  );
8377 
8378  auto pc = convertPixelToPercent(output
8379  , px.first
8380  , px.second
8381  );
8382 
8383  window_data.size_mm = window_data.size_mm;
8384  window_data.size_percent = { pc.first, pc.second };
8385  window_data.size_pixel = { px.first, px.second };
8386  }
8387  else if(window_data.size_unit == Yetani::SizeUnit::Percent)
8388  {
8389  auto px = convertPercentToPixel(output
8390  , window_data.size_percent.width
8391  , window_data.size_percent.height
8392  );
8393 
8394  auto mm = convertPixelToMm(output
8395  , px.first
8396  , px.second
8397  );
8398 
8399  window_data.size_mm = { mm.first, mm.second };
8400  window_data.size_percent = window_data.size_percent;
8401  window_data.size_pixel = { px.first, px.second };
8402  }
8403  else if(window_data.size_unit == Yetani::SizeUnit::Pixel)
8404  {
8405  auto mm = convertPixelToMm(output
8406  , window_data.size_pixel.width
8407  , window_data.size_pixel.height
8408  );
8409 
8410  auto pc = convertPixelToPercent(output
8411  , window_data.size_pixel.width
8412  , window_data.size_pixel.height
8413  );
8414 
8415  window_data.size_mm = { mm.first, mm.second };
8416  window_data.size_percent = { pc.first, pc.second };
8417  window_data.size_pixel = window_data.size_pixel;
8418  }
8419 
8420  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8421 }
8422 
8423 
8427 void Yetani::windowInitMemory(Yetani::WindowData& window_data
8428  , Yetani::Window::Memory& window_memory
8429  ) noexcept
8430 {
8431  size_t size_in_bytes = sizeInBytes(window_data.size_pixel
8432  , window_data.pixel_format
8433  ) * 3;
8434 
8435  window_data.error = window_memory.memory_pool.init(size_in_bytes
8436  , true
8437  , zakero::MemoryPool::Alignment::Bits_32
8438  );
8439 
8440  if(window_data.error)
8441  {
8442  return;
8443  }
8444 
8445  window_memory.wl_shm_pool = wl_shm_create_pool(window_data.wl_shm
8446  , window_memory.memory_pool.fd()
8447  , window_memory.memory_pool.size()
8448  );
8449 
8450  window_memory.memory_pool.sizeOnChange([&](size_t new_size)
8451  {
8452  wl_shm_pool_resize(window_memory.wl_shm_pool, new_size);
8453  });
8454 
8455  window_data.error = ZAKERO_YETANI__ERROR(Error_None);
8456 }
8457 
8458 
8462 void Yetani::windowInitOutput(Yetani::WindowData& window_data
8463  , struct wl_surface* wl_surface
8464  ) noexcept
8465 {
8466  std::lock_guard<std::mutex> lock(output_data.mutex);
8467 
8468  output_data.surface_output_map[wl_surface].push_back(window_data.wl_output);
8469 }
8470 
8471 
8475 void Yetani::windowEraseMemory(Yetani::Window::Memory& window_memory
8476  ) noexcept
8477 {
8478  if(window_memory.wl_shm_pool)
8479  {
8480  wl_shm_pool_destroy(window_memory.wl_shm_pool);
8481  window_memory.wl_shm_pool = nullptr;
8482  }
8483 }
8484 
8485 
8489 void Yetani::windowEraseOutput(struct wl_surface* wl_surface
8490  ) noexcept
8491 {
8492  std::lock_guard<std::mutex> lock(output_data.mutex);
8493 
8494  if(output_data.surface_output_map.contains(wl_surface))
8495  {
8496  output_data.surface_output_map.erase(wl_surface);
8497  }
8498 }
8499 
8500 
8504 void Yetani::windowEraseSurfaceExtent(struct wl_surface* wl_surface
8505  ) noexcept
8506 {
8507  std::lock_guard<std::mutex> lock(surface_extent_mutex);
8508 
8509  if(surface_extent_map.contains(wl_surface))
8510  {
8511  surface_extent_map.erase(wl_surface);
8512  }
8513 }
8514 
8515 
8519 void Yetani::windowAdd(Yetani::Window* window
8520  ) noexcept
8521 {
8522  std::lock_guard<std::mutex> lock(window_vector_mutex);
8523 
8524  window_vector.push_back(window);
8525 }
8526 
8527 
8531 void Yetani::windowRemove(Yetani::Window* window
8532  ) noexcept
8533 {
8534  std::lock_guard<std::mutex> lock(window_vector_mutex);
8535 
8536  zakero::vectorErase(window_vector, window);
8537 }
8538 
8539 // }}}
8540 // {{{ Window : Documentation
8541 
8707 // }}}
8708 // {{{ Window : Constructor / Destructor
8709 
8738  )
8739  : yetani {((Yetani::WindowData*)ptr)->yetani}
8740  , wl_buffer {nullptr}
8741  , wl_surface {nullptr}
8742  , xdg_surface {nullptr}
8743  , xdg_toplevel {nullptr}
8744  , xdg_decoration {nullptr}
8745  , window_memory {nullptr, ((Yetani::WindowData*)ptr)->file_name}
8746  , pixel_format {((Yetani::WindowData*)ptr)->pixel_format}
8747 {
8748  Yetani::WindowData& window_data = *((Yetani::WindowData*)ptr);
8749 
8750  yetani->windowInitMemory(window_data, window_memory);
8751  if(window_data.error)
8752  {
8753  return;
8754  }
8755 
8756  wl_surface = yetani->surfaceCreate(yetani
8757  , pixel_format
8758  , window_data.size_pixel
8759  , false
8760  , window_memory
8761  );
8762 
8763  xdg_surface = yetani->xdgSurfaceCreate(wl_surface);
8764 
8765  yetani->xdgSurfaceSetExtent(wl_surface
8766  , window_data.size_unit
8767  , window_data.size_mm
8768  , window_data.size_percent
8769  , window_data.size_pixel
8770  );
8771 
8772  xdg_toplevel = yetani->xdgToplevelCreate(xdg_surface);
8773 
8774  xdg_decoration = yetani->xdgDecorationCreate(xdg_surface, xdg_toplevel);
8775 
8776  wl_surface_commit(wl_surface);
8777 
8778  yetani->windowInitOutput(window_data, wl_surface);
8779  if(window_data.error)
8780  {
8781  return;
8782  }
8783 
8784  yetani->windowAdd(this);
8785 }
8786 
8787 
8792 {
8793  yetani->windowRemove(this);
8794 
8795  if(xdg_decoration != nullptr)
8796  {
8797  yetani->xdgDecorationDestroy(xdg_surface, xdg_toplevel, xdg_decoration);
8798  }
8799 
8800  if(xdg_toplevel != nullptr)
8801  {
8802  yetani->xdgToplevelDestroy(xdg_surface, xdg_toplevel);
8803  }
8804 
8805  if(xdg_surface != nullptr)
8806  {
8807  yetani->xdgSurfaceDestroy(wl_surface, xdg_surface);
8808  }
8809 
8810  if(wl_surface != nullptr)
8811  {
8812  yetani->windowEraseOutput(wl_surface);
8813  yetani->surfaceDestroy(yetani, wl_surface);
8814  yetani->windowEraseSurfaceExtent(wl_surface);
8815  }
8816 
8817  yetani->windowEraseMemory(window_memory);
8818 }
8819 
8820 // }}}
8821 // {{{ Window : Cursor
8822 
8836 std::error_code Yetani::Window::cursorUse(const std::string& name
8837  ) noexcept
8838 {
8839  if(name.empty())
8840  {
8841  return yetani->cursorDetach(wl_surface);
8842  }
8843 
8844  return yetani->cursorAttach(name, wl_surface);
8845 }
8846 
8847 
8854 {
8855  yetani->cursorHide(wl_surface);
8856 }
8857 
8858 
8865 {
8866  yetani->cursorShow(wl_surface);
8867 }
8868 
8869 // }}}
8870 // {{{ Window : Settings
8871 
8888 void Yetani::Window::setClass(const std::string& class_name
8889  ) noexcept
8890 {
8891  xdg_toplevel_set_app_id(xdg_toplevel, class_name.c_str());
8892 }
8893 
8894 
8901 void Yetani::Window::setTitle(const std::string& title
8902  ) noexcept
8903 {
8904  xdg_toplevel_set_title(xdg_toplevel, title.c_str());
8905 }
8906 
8907 
8928  ) noexcept
8929 {
8930  if(yetani->decoration_manager == nullptr)
8931  {
8932  return ZAKERO_YETANI__ERROR(Error_Server_Side_Decorations_Not_Available);
8933  }
8934 
8935  uint32_t decoration_state = decorations == Yetani::WindowDecorations::Server_Side
8936  ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
8937  : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE
8938  ;
8939 
8940  zxdg_toplevel_decoration_v1_set_mode(xdg_decoration
8941  , decoration_state
8942  );
8943 
8944  return ZAKERO_YETANI__ERROR(Error_None);
8945 }
8946 
8947 
8956 {
8957  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
8958 
8959  Yetani::WindowMode window_mode = Yetani::toWindowMode(toplevel.window_state);
8960 
8961  return window_mode;
8962 }
8963 
8964 
8974  ) noexcept
8975 {
8976  XdgState window_state = Yetani::toXdgState(window_mode);
8977 
8978  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
8979 
8980  if(toplevel.window_state == window_state)
8981  {
8982  return true;
8983  }
8984 
8985  return false;
8986 }
8987 
8988 
8998  ) noexcept
8999 {
9000  XdgState window_state = Yetani::toXdgState(window_mode);
9001 
9002  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9003 
9004  if(toplevel.window_state == window_state)
9005  {
9006  return;
9007  }
9008 
9009  switch(window_mode)
9010  {
9012  xdg_toplevel_set_fullscreen(xdg_toplevel, nullptr);
9013  break;
9014 
9015  case WindowMode::Maximized:
9016  xdg_toplevel_set_maximized(xdg_toplevel);
9017  break;
9018 
9019  case WindowMode::Normal:
9020  xdg_toplevel_unset_fullscreen(xdg_toplevel);
9021  xdg_toplevel_unset_maximized(xdg_toplevel);
9022  break;
9023  }
9024 }
9025 
9026 
9043 std::error_code Yetani::Window::setSize(const Yetani::SizeMm& size
9044  ) noexcept
9045 {
9046  if(size.width <= 0 || size.height <= 0)
9047  {
9048  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9049  }
9050 
9051  Yetani::SizePixel size_pixel = convertToPixel(size);
9052 
9053  if(size_pixel.width <= 0)
9054  {
9055  size_pixel.width = 1;
9056  }
9057 
9058  if(size_pixel.height <= 0)
9059  {
9060  size_pixel.height = 1;
9061  }
9062 
9063  yetani->surface_resize_mutex_map[wl_surface].lock();
9064  {
9065  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9066 
9067  surface_extent.preferred_unit = Yetani::SizeUnit::Millimeter;
9068  surface_extent.preferred_mm = size;
9069  surface_extent.size_pixel = size_pixel;
9070 
9071  surfaceCalculateSize(yetani, wl_surface, size_pixel);
9072  }
9073  yetani->surface_resize_mutex_map[wl_surface].unlock();
9074 
9075  return ZAKERO_YETANI__ERROR(Error_None);
9076 }
9077 
9078 
9095 std::error_code Yetani::Window::setSize(const Yetani::SizePercent& size
9096  ) noexcept
9097 {
9098  if(size.width <= 0 || size.height <= 0)
9099  {
9100  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9101  }
9102 
9103  Yetani::SizePixel size_pixel = convertToPixel(size);
9104 
9105  if(size_pixel.width <= 0)
9106  {
9107  size_pixel.width = 1;
9108  }
9109 
9110  if(size_pixel.height <= 0)
9111  {
9112  size_pixel.height = 1;
9113  }
9114 
9115  yetani->surface_resize_mutex_map[wl_surface].lock();
9116  {
9117  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9118 
9119  surface_extent.preferred_unit = Yetani::SizeUnit::Percent;
9120  surface_extent.preferred_percent = size;
9121  surface_extent.size_pixel = size_pixel;
9122 
9123  surfaceCalculateSize(yetani, wl_surface, size_pixel);
9124  }
9125  yetani->surface_resize_mutex_map[wl_surface].unlock();
9126 
9127  return ZAKERO_YETANI__ERROR(Error_None);
9128 }
9129 
9130 
9147 std::error_code Yetani::Window::setSize(const Yetani::SizePixel& size
9148  ) noexcept
9149 {
9150  if(size.width <= 0 || size.height <= 0)
9151  {
9152  return ZAKERO_YETANI__ERROR(Error_Window_Size_Too_Small);
9153  }
9154 
9155  yetani->surface_resize_mutex_map[wl_surface].lock();
9156  {
9157  Yetani::SurfaceExtent& surface_extent = yetani->surface_extent_map[wl_surface];
9158 
9159  surface_extent.preferred_unit = Yetani::SizeUnit::Pixel;
9160  surface_extent.size_pixel = size;
9161 
9162  surfaceCalculateSize(yetani, wl_surface, size);
9163  }
9164  yetani->surface_resize_mutex_map[wl_surface].unlock();
9165 
9166  return ZAKERO_YETANI__ERROR(Error_None);
9167 }
9168 
9169 
9181 std::error_code Yetani::Window::setSizeMinMax(const Yetani::SizeMm& size_min
9182  , const Yetani::SizeMm& size_max
9183  ) noexcept
9184 {
9185  std::error_code error = validateMinMax<Yetani::SizeMm>(size_min, size_max);
9186  if(error)
9187  {
9188  return error;
9189  }
9190 
9191  Yetani::SizePixel size_pixel_min;
9192  Yetani::SizePixel size_pixel_max;
9193 
9194  {
9195  Yetani::OutputData& output_data = yetani->output_data;
9196 
9197  std::lock_guard<std::mutex> lock(output_data.mutex);
9198 
9199  Yetani::VectorWlOutput& vector = output_data.surface_output_map[wl_surface];
9200  struct wl_output* wl_output = vector.front();
9201  const Yetani::Output& output = output_data.output_map[wl_output];
9202 
9203  auto min = yetani->convertMmToPixel(output, size_min.width, size_min.height);
9204  size_pixel_min = { min.first, min.second };
9205 
9206  auto max = yetani->convertMmToPixel(output, size_max.width, size_max.height);
9207  size_pixel_max = { max.first, max.second };
9208  }
9209 
9210  yetani->xdgToplevelSizeMinMaxChange(yetani
9211  , xdg_toplevel
9212  , wl_surface
9213  , size_pixel_min
9214  , size_pixel_max
9215  );
9216 
9217  return ZAKERO_YETANI__ERROR(Error_None);
9218 }
9219 
9220 
9232 std::error_code Yetani::Window::setSizeMinMax(const Yetani::SizePercent& size_min
9233  , const Yetani::SizePercent& size_max
9234  ) noexcept
9235 {
9236  std::error_code error = validateMinMax<Yetani::SizePercent>(size_min, size_max);
9237  if(error)
9238  {
9239  return error;
9240  }
9241 
9242  Yetani::SizePixel size_pixel_min;
9243  Yetani::SizePixel size_pixel_max;
9244 
9245  {
9246  Yetani::OutputData& output_data = yetani->output_data;
9247 
9248  std::lock_guard<std::mutex> lock(output_data.mutex);
9249 
9250  Yetani::VectorWlOutput& vector = output_data.surface_output_map[wl_surface];
9251  struct wl_output* wl_output = vector.front();
9252  const Yetani::Output& output = output_data.output_map[wl_output];
9253 
9254  auto min = yetani->convertPercentToPixel(output, size_min.width, size_min.height);
9255  size_pixel_min = { min.first, min.second };
9256 
9257  auto max = yetani->convertPercentToPixel(output, size_max.width, size_max.height);
9258  size_pixel_max = { max.first, max.second };
9259  }
9260 
9261  yetani->xdgToplevelSizeMinMaxChange(yetani
9262  , xdg_toplevel
9263  , wl_surface
9264  , size_pixel_min
9265  , size_pixel_max
9266  );
9267 
9268  return ZAKERO_YETANI__ERROR(Error_None);
9269 }
9270 
9271 
9283 std::error_code Yetani::Window::setSizeMinMax(const Yetani::SizePixel& size_min
9284  , const Yetani::SizePixel& size_max
9285  ) noexcept
9286 {
9287  std::error_code error = validateMinMax<Yetani::SizePixel>(size_min, size_max);
9288  if(error)
9289  {
9290  return error;
9291  }
9292 
9293  yetani->xdgToplevelSizeMinMaxChange(yetani
9294  , xdg_toplevel
9295  , wl_surface
9296  , size_min
9297  , size_max
9298  );
9299 
9300  return ZAKERO_YETANI__ERROR(Error_None);
9301 }
9302 
9303 // }}}
9304 // {{{ Window : Rendering
9305 
9342 std::error_code Yetani::Window::imageNext(uint8_t*& image
9343  , Yetani::SizePixel& size
9344  ) noexcept
9345 {
9346  if(wl_buffer != nullptr)
9347  {
9348  bufferDestroy(wl_buffer);
9349  }
9350 
9351  Yetani::SurfaceSize& surface_size = yetani->surface_size_map[wl_surface];
9352 
9353  yetani->surface_resize_mutex_map[wl_surface].lock();
9354  {
9355  wl_buffer = bufferCreateAndRelease(yetani
9356  , surface_size
9357  , &window_memory
9358  );
9359  }
9360  yetani->surface_resize_mutex_map[wl_surface].unlock();
9361 
9362  image = window_memory.memory_pool.addressOf(
9363  yetani->buffer.map[wl_buffer].offset
9364  );
9365 
9366  size = { surface_size.width, surface_size.height };
9367 
9368  return ZAKERO_YETANI__ERROR(Error_None);
9369 }
9370 
9371 
9379 {
9380  if(wl_buffer == nullptr)
9381  {
9382  // This nullptr check is needed because:
9383  // - If imagePresent() is called before imageNext() then
9384  // wl_buffer could be nullptr.
9385  // - There is a chance that a valid "buffer_next" can be
9386  // replaced with a nullptr, and this will cause a
9387  // frame-drop.
9388 
9389  return;
9390  }
9391 
9392  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
9393 
9394  wl_buffer = surface_frame.buffer_next.exchange(wl_buffer);
9395 }
9396 
9397 
9410 uint32_t Yetani::Window::time() const noexcept
9411 {
9412  Yetani::SurfaceFrame& surface_frame = yetani->surface_frame_map[wl_surface];
9413 
9414  return surface_frame.time_ms;
9415 }
9416 
9417 // }}}
9418 // {{{ Window : Misc
9419 
9428 uint8_t Yetani::Window::bytesPerPixel() const noexcept
9429 {
9430  return yetani->shmFormatBytesPerPixel(pixel_format);
9431 }
9432 
9433 
9442 {
9443  xdg_toplevel_set_minimized(xdg_toplevel);
9444 }
9445 
9446 // }}}
9447 // {{{ Window : Measurement Conversion
9448 
9457  ) const noexcept
9458 {
9459  const Yetani::OutputData& output_data = yetani->output_data;
9460 
9461  std::lock_guard<std::mutex> lock(output_data.mutex);
9462 
9463  struct wl_output* wl_output = output_data.surface_output_map.at(wl_surface).front();
9464  const Yetani::Output& output = output_data.output_map.at(wl_output);
9465 
9466  auto p = yetani->convertPixelToMm(output, point.x, point.y);
9467 
9468  return { point.time, p.first, p.second };
9469 }
9470 
9471 
9480  ) const noexcept
9481 {
9482  const Yetani::OutputData& output_data = yetani->output_data;
9483 
9484  std::lock_guard<std::mutex> lock(output_data.mutex);
9485 
9486  struct wl_output* wl_output = output_data.surface_output_map.at(wl_surface).front();
9487  const Yetani::Output& output = output_data.output_map.at(wl_output);
9488 
9489  auto p = yetani->convertPixelToPercent(output, point.x, point.y);
9490 
9491  return { point.time, p.first, p.second };
9492 }
9493 
9494 
9503  ) const noexcept
9504 {
9505  Yetani::OutputData& output_data = yetani->output_data;
9506 
9507  std::lock_guard<std::mutex> lock(output_data.mutex);
9508 
9509  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9510  const Yetani::Output& output = output_data.output_map[wl_output];
9511 
9512  auto p = yetani->convertMmToPixel(output, point.x, point.y);
9513 
9514  return { point.time, p.first, p.second };
9515 }
9516 
9517 
9526  ) const noexcept
9527 {
9528  Yetani::OutputData& output_data = yetani->output_data;
9529 
9530  std::lock_guard<std::mutex> lock(output_data.mutex);
9531 
9532  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9533  const Yetani::Output& output = output_data.output_map[wl_output];
9534 
9535  auto p = yetani->convertPercentToPixel(output, point.x, point.y);
9536 
9537  return { point.time, p.first, p.second };
9538 }
9539 
9540 
9549  ) const noexcept
9550 {
9551  Yetani::OutputData& output_data = yetani->output_data;
9552 
9553  std::lock_guard<std::mutex> lock(output_data.mutex);
9554 
9555  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9556  const Yetani::Output& output = output_data.output_map[wl_output];
9557 
9558  auto p = yetani->convertPixelToMm(output, size.width, size.height);
9559 
9560  return { p.first, p.second };
9561 }
9562 
9563 
9572  ) const noexcept
9573 {
9574  Yetani::OutputData& output_data = yetani->output_data;
9575 
9576  std::lock_guard<std::mutex> lock(output_data.mutex);
9577 
9578  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9579  const Yetani::Output& output = output_data.output_map[wl_output];
9580 
9581  auto p = yetani->convertPixelToPercent(output, size.width, size.height);
9582 
9583  return { p.first, p.second };
9584 }
9585 
9586 
9595  ) const noexcept
9596 {
9597  Yetani::OutputData& output_data = yetani->output_data;
9598 
9599  std::lock_guard<std::mutex> lock(output_data.mutex);
9600 
9601  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9602  const Yetani::Output& output = output_data.output_map[wl_output];
9603 
9604  auto p = yetani->convertMmToPixel(output, size.width, size.height);
9605 
9606  return { p.first, p.second };
9607 }
9608 
9609 
9618  ) const noexcept
9619 {
9620  Yetani::OutputData& output_data = yetani->output_data;
9621 
9622  std::lock_guard<std::mutex> lock(output_data.mutex);
9623 
9624  struct wl_output* wl_output = output_data.surface_output_map[wl_surface].front();
9625  const Yetani::Output& output = output_data.output_map[wl_output];
9626 
9627  auto p = yetani->convertPercentToPixel(output, size.width, size.height);
9628 
9629  return { p.first, p.second };
9630 }
9631 
9632 // }}}
9633 // {{{ Window : Event Handling
9634 
9647  ) noexcept
9648 {
9649  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9650 
9651  if(lambda == nullptr)
9652  {
9653  toplevel.close_request_lambda = Lambda_DoNothing;
9654  }
9655  else
9656  {
9657  toplevel.close_request_lambda = lambda;
9658  }
9659 }
9660 
9661 
9672  ) noexcept
9673 {
9674  XdgDecoration& decoration = yetani->xdg_decoration_map[xdg_surface];
9675 
9676  if(lambda == nullptr)
9677  {
9678  decoration.lambda = LambdaWindowDecorations_DoNothing;
9679  }
9680  else
9681  {
9682  decoration.lambda = lambda;
9683  }
9684 }
9685 
9686 
9701  ) noexcept
9702 {
9703  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9704 
9705  if(lambda == nullptr)
9706  {
9707  toplevel.is_active_lambda = LambdaBool_DoNothing;
9708  }
9709  else
9710  {
9711  toplevel.is_active_lambda = lambda;
9712  }
9713 }
9714 
9715 
9722  ) noexcept
9723 {
9724  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9725  {
9726  return;
9727  }
9728 
9729  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9730 
9731  if(lambda == nullptr)
9732  {
9733  event.on_enter = Lambda_DoNothing;
9734  }
9735  else
9736  {
9737  event.on_enter = lambda;
9738  }
9739 }
9740 
9741 
9748  ) noexcept
9749 {
9750  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9751  {
9752  return;
9753  }
9754 
9755  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9756 
9757  if(lambda == nullptr)
9758  {
9759  event.on_leave = Lambda_DoNothing;
9760  }
9761  else
9762  {
9763  event.on_leave = lambda;
9764  }
9765 }
9766 
9767 
9776  ) noexcept
9777 {
9778  if(yetani->keyboard.event_map.contains(wl_surface) == false)
9779  {
9780  return;
9781  }
9782 
9783  Yetani::KeyboardEvent& event = yetani->keyboard.event_map[wl_surface];
9784 
9785  if(lambda == nullptr)
9786  {
9787  event.on_key = LambdaKey_DoNothing;
9788  }
9789  else
9790  {
9791  event.on_key = lambda;
9792  }
9793 }
9794 
9795 
9803  ) noexcept
9804 {
9805  XdgToplevel& toplevel = yetani->xdg_toplevel_map[xdg_surface];
9806 
9807  if(lambda == nullptr)
9808  {
9809  toplevel.window_state_lambda = LambdaWindowMode_DoNothing;
9810  }
9811  else
9812  {
9813  toplevel.window_state_lambda = lambda;
9814  }
9815 }
9816 
9817 
9832  ) noexcept
9833 {
9834  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9835 
9836  if(lambda == nullptr)
9837  {
9838  event.on_size_mm_change = LambdaSizeMm_DoNothing;
9839  }
9840  else
9841  {
9842  event.on_size_mm_change = lambda;
9843  }
9844 }
9845 
9846 
9861  ) noexcept
9862 {
9863  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9864 
9865  if(lambda == nullptr)
9866  {
9867  event.on_size_percent_change = LambdaSizePercent_DoNothing;
9868  }
9869  else
9870  {
9871  event.on_size_percent_change = lambda;
9872  }
9873 }
9874 
9875 
9890  ) noexcept
9891 {
9892  Yetani::SurfaceEvent& event = yetani->surface_event_map[wl_surface];
9893 
9894  if(lambda == nullptr)
9895  {
9896  event.on_size_pixel_change = LambdaSizePixel_DoNothing;
9897  }
9898  else
9899  {
9900  event.on_size_pixel_change = lambda;
9901  }
9902 }
9903 
9904 
9913  ) noexcept
9914 {
9915  if(yetani->pointer.event_map.contains(wl_surface) == false)
9916  {
9917  return;
9918  }
9919 
9920  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9921 
9922  if(lambda == nullptr)
9923  {
9924  event.on_button_mm = LambdaButtonMm_DoNothing;
9925  }
9926  else
9927  {
9928  event.on_button_mm = lambda;
9929  }
9930 }
9931 
9932 
9941  ) noexcept
9942 {
9943  if(yetani->pointer.event_map.contains(wl_surface) == false)
9944  {
9945  return;
9946  }
9947 
9948  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9949 
9950  if(lambda == nullptr)
9951  {
9952  event.on_button_percent = LambdaButtonPercent_DoNothing;
9953  }
9954  else
9955  {
9956  event.on_button_percent = lambda;
9957  }
9958 }
9959 
9960 
9969  ) noexcept
9970 {
9971  if(yetani->pointer.event_map.contains(wl_surface) == false)
9972  {
9973  return;
9974  }
9975 
9976  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
9977 
9978  if(lambda == nullptr)
9979  {
9980  event.on_button_pixel = LambdaButtonPixel_DoNothing;
9981  }
9982  else
9983  {
9984  event.on_button_pixel = lambda;
9985  }
9986 }
9987 
9988 
10000  ) noexcept
10001 {
10002  if(yetani->pointer.event_map.contains(wl_surface) == false)
10003  {
10004  return;
10005  }
10006 
10007  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10008 
10009  if(lambda == nullptr)
10010  {
10011  event.on_enter_mm = LambdaPointMm_DoNothing;
10012  }
10013  else
10014  {
10015  event.on_enter_mm = lambda;
10016  }
10017 }
10018 
10019 
10031  ) noexcept
10032 {
10033  if(yetani->pointer.event_map.contains(wl_surface) == false)
10034  {
10035  return;
10036  }
10037 
10038  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10039 
10040  if(lambda == nullptr)
10041  {
10042  event.on_enter_percent = LambdaPointPercent_DoNothing;
10043  }
10044  else
10045  {
10046  event.on_enter_percent = lambda;
10047  }
10048 }
10049 
10050 
10062  ) noexcept
10063 {
10064  if(yetani->pointer.event_map.contains(wl_surface) == false)
10065  {
10066  return;
10067  }
10068 
10069  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10070 
10071  if(lambda == nullptr)
10072  {
10073  event.on_enter_pixel = LambdaPointPixel_DoNothing;
10074  }
10075  else
10076  {
10077  event.on_enter_pixel = lambda;
10078  }
10079 }
10080 
10081 
10090  ) noexcept
10091 {
10092  if(yetani->pointer.event_map.contains(wl_surface) == false)
10093  {
10094  return;
10095  }
10096 
10097  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10098 
10099  if(lambda == nullptr)
10100  {
10101  event.on_leave = Lambda_DoNothing;
10102  }
10103  else
10104  {
10105  event.on_leave = lambda;
10106  }
10107 }
10108 
10109 
10118  ) noexcept
10119 {
10120  if(yetani->pointer.event_map.contains(wl_surface) == false)
10121  {
10122  return;
10123  }
10124 
10125  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10126 
10127  if(lambda == nullptr)
10128  {
10129  event.on_motion_mm = LambdaPointMm_DoNothing;
10130  }
10131  else
10132  {
10133  event.on_motion_mm = lambda;
10134  }
10135 }
10136 
10137 
10146  ) noexcept
10147 {
10148  if(yetani->pointer.event_map.contains(wl_surface) == false)
10149  {
10150  return;
10151  }
10152 
10153  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10154 
10155  if(lambda == nullptr)
10156  {
10157  event.on_motion_percent = LambdaPointPercent_DoNothing;
10158  }
10159  else
10160  {
10161  event.on_motion_percent = lambda;
10162  }
10163 }
10164 
10165 
10174  ) noexcept
10175 {
10176  if(yetani->pointer.event_map.contains(wl_surface) == false)
10177  {
10178  return;
10179  }
10180 
10181  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10182 
10183  if(lambda == nullptr)
10184  {
10185  event.on_motion_pixel = LambdaPointPixel_DoNothing;
10186  }
10187  else
10188  {
10189  event.on_motion_pixel = lambda;
10190  }
10191 }
10192 
10193 
10201  ) noexcept
10202 {
10203  if(yetani->pointer.event_map.contains(wl_surface) == false)
10204  {
10205  return;
10206  }
10207 
10208  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10209 
10210  if(lambda == nullptr)
10211  {
10212  event.on_axis = LambdaAxis_DoNothing;
10213  }
10214  else
10215  {
10216  event.on_axis = lambda;
10217  }
10218 }
10219 
10220 
10228  ) noexcept
10229 {
10230  if(yetani->pointer.event_map.contains(wl_surface) == false)
10231  {
10232  return;
10233  }
10234 
10235  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10236 
10237  if(lambda == nullptr)
10238  {
10239  event.on_axis_source = Lambda_DoNothing;
10240  }
10241  else
10242  {
10243  event.on_axis_source = lambda;
10244  }
10245 }
10246 
10247 
10255  ) noexcept
10256 {
10257  if(yetani->pointer.event_map.contains(wl_surface) == false)
10258  {
10259  return;
10260  }
10261 
10262  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10263 
10264  if(lambda == nullptr)
10265  {
10266  event.on_axis_stop = Lambda_DoNothing;
10267  }
10268  else
10269  {
10270  event.on_axis_stop = lambda;
10271  }
10272 }
10273 
10274 
10282  ) noexcept
10283 {
10284  if(yetani->pointer.event_map.contains(wl_surface) == false)
10285  {
10286  return;
10287  }
10288 
10289  Yetani::PointerEvent& event = yetani->pointer.event_map[wl_surface];
10290 
10291  if(lambda == nullptr)
10292  {
10293  event.on_axis_discrete = Lambda_DoNothing;
10294  }
10295  else
10296  {
10297  event.on_axis_discrete = lambda;
10298  }
10299 }
10300 
10301 // }}}
10302 // {{{ Window : Helpers
10303 
10304 
10305 // }}}
10306 // {{{ Convenience
10307 
10315 std::string to_string(const std::error_code& error
10316  ) noexcept
10317 {
10318  std::string str = std::string(error.category().name())
10319  + ":" + std::to_string(error.value())
10320  + ":" + std::string(error.message())
10321  ;
10322 
10323  return str;
10324 }
10325 
10326 
10334 std::string to_string(const wl_shm_format shm_format
10335  ) noexcept
10336 {
10337  return Yetani::shmFormatName(shm_format);
10338 }
10339 
10340 
10349 std::string to_string(const Yetani::KeyModifier& key_modifier
10350  ) noexcept
10351 {
10352  auto mod_to_str = [](std::string& s, uint32_t m)
10353  {
10354  s += "[";
10355  std::string delim = "";
10356 
10358  {
10359  s += delim + "\"Shift\"";
10360  delim = ",";
10361  }
10362 
10364  {
10365  s += delim + "\"CapsLock\"";
10366  delim = ",";
10367  }
10368 
10370  {
10371  s += delim + "\"Control\"";
10372  delim = ",";
10373  }
10374 
10375  if(m & Yetani::KeyModifier_Alt)
10376  {
10377  s += delim + "\"Alt\"";
10378  delim = ",";
10379  }
10380 
10381  if(m & Yetani::KeyModifier_Meta)
10382  {
10383  s += delim + "\"Meta\"";
10384  }
10385 
10386  s += "]";
10387  };
10388 
10389  std::string str = "{ \"pressed\": ";
10390  mod_to_str(str, key_modifier.pressed);
10391 
10392  str += ", \"latched\": ";
10393  mod_to_str(str, key_modifier.latched);
10394 
10395  str += ", \"locked\": ";
10396  mod_to_str(str, key_modifier.locked);
10397 
10398  str += " }";
10399 
10400  return str;
10401 }
10402 
10403 
10411 std::string to_string(const Yetani::KeyState key_state
10412  ) noexcept
10413 {
10414  switch(key_state)
10415  {
10416  case Yetani::KeyState::Pressed: return "Pressed";
10417  case Yetani::KeyState::Released: return "Released";
10418  case Yetani::KeyState::Repeat: return "Repeat";
10419  default: return "";
10420  }
10421 }
10422 
10423 
10431 std::string to_string(const Yetani::Output& output
10432  ) noexcept
10433 {
10434  return "{\tx: " + std::to_string(output.x)
10435  + "\n,\ty: " + std::to_string(output.y)
10436  + "\n,\tphysical_width_mm: " + std::to_string(output.physical_width_mm)
10437  + "\n,\tphysical_height_mm: " + std::to_string(output.physical_height_mm)
10438  + "\n,\tsubpixel: " + std::to_string(output.subpixel)
10439  + "\n,\tsubpixel_name: \"" + Yetani::outputSubpixelName(output.subpixel) + "\""
10440  + "\n,\tmake: \"" + output.make + "\""
10441  + "\n,\tmodel: \"" + output.model + "\""
10442  + "\n,\ttransform: " + std::to_string(output.transform)
10443  + "\n,\ttransform_name: \"" + Yetani::outputTransformName(output.transform) + "\""
10444  + "\n,\tflags: " + std::to_string(output.flags)
10445  + "\n,\twidth: " + std::to_string(output.width)
10446  + "\n,\theight: " + std::to_string(output.height)
10447  + "\n,\trefresh_mHz: " + std::to_string(output.refresh_mHz)
10448  + "\n,\tscale_factor: " + std::to_string(output.scale_factor)
10449  + "\n,\tpixels_per_mm_horizontal: " + std::to_string(output.pixels_per_mm_horizontal)
10450  + "\n,\tpixels_per_mm_vertical: " + std::to_string(output.pixels_per_mm_vertical)
10451  + "\n}";
10452 }
10453 
10454 
10462 std::string to_string(const Yetani::PointerAxisSource source
10463  ) noexcept
10464 {
10465  switch(source)
10466  {
10467  case Yetani::PointerAxisSource::Continuous: return "Continuous";
10468  case Yetani::PointerAxisSource::Finger: return "Finger";
10469  case Yetani::PointerAxisSource::Wheel: return "Wheel";
10470  case Yetani::PointerAxisSource::Wheel_Tilt: return "Wheel Tilt";
10471  case Yetani::PointerAxisSource::Unknown: [[fallthrough]];
10472  default: return "";
10473  }
10474 }
10475 
10476 
10484 std::string to_string(const Yetani::PointerAxisType type
10485  ) noexcept
10486 {
10487  switch(type)
10488  {
10489  case Yetani::PointerAxisType::Horizontal: return "Horizontal";
10490  case Yetani::PointerAxisType::Vertical: return "Vertical";
10491  case Yetani::PointerAxisType::Unknown: [[fallthrough]];
10492  default: return "";
10493  }
10494 }
10495 
10496 
10504 std::string to_string(const Yetani::PointerButtonState button_state
10505  ) noexcept
10506 {
10507  switch(button_state)
10508  {
10509  case Yetani::PointerButtonState::Pressed: return "Pressed";
10510  case Yetani::PointerButtonState::Released: return "Released";
10511  default: return "";
10512  }
10513 }
10514 
10515 
10523 std::string to_string(const Yetani::WindowMode window_mode
10524  ) noexcept
10525 {
10526  switch(window_mode)
10527  {
10528  case Yetani::WindowMode::Fullscreen: return "Fullscreen";
10529  case Yetani::WindowMode::Maximized: return "Maximized";
10530  case Yetani::WindowMode::Normal: return "Normal";
10531  default: return "";
10532  }
10533 }
10534 
10535 
10550  , Yetani::PointMm& rhs
10551  ) noexcept
10552 {
10553  return equalish(lhs.x, rhs.x, 0.001)
10554  && equalish(lhs.y, rhs.y, 0.001)
10555  ;
10556 }
10557 
10558 
10573  , Yetani::PointPercent& rhs
10574  ) noexcept
10575 {
10576  return equalish(lhs.x, rhs.x, 0.00001)
10577  && equalish(lhs.y, rhs.y, 0.00001)
10578  ;
10579 }
10580 
10581 
10593  , Yetani::PointPixel& rhs
10594  ) noexcept
10595 {
10596  return (lhs.x == rhs.x) && (lhs.y == rhs.y);
10597 }
10598 
10599 
10612  , Yetani::SizeMm& rhs
10613  ) noexcept
10614 {
10615  return equalish(lhs.width, rhs.width, 0.001)
10616  && equalish(lhs.height, rhs.height, 0.001)
10617  ;
10618 }
10619 
10620 
10633  , Yetani::SizePercent& rhs
10634  ) noexcept
10635 {
10636  return equalish(lhs.width, rhs.width, 0.00001)
10637  && equalish(lhs.height, rhs.height, 0.00001)
10638  ;
10639 }
10640 
10641 
10651  , Yetani::SizePixel& rhs
10652  ) noexcept
10653 {
10654  return (lhs.width == rhs.width) && (lhs.height == rhs.height);
10655 }
10656 
10657 // }}}
10658 
10659 };
10660 
10661 #endif // ZAKERO_YETANI_IMPLEMENTATION
10662 
10663 // }}}
10664 
10665 #endif // zakero_Yetani_h
zakero::MemoryPool::size
size_t size() const noexcept
The size of the memory pool.
Definition: Zakero_MemoryPool.h:735
zakero::Yetani::SizePixel::operator==
friend bool operator==(Yetani::SizePixel &, Yetani::SizePixel &) noexcept
Compare two Size objects.
Definition: Zakero_Yetani.h:10650
zakero::Yetani::Window::pointerOnAxis
void pointerOnAxis(Yetani::LambdaAxis) noexcept
Respond to "Pointer Axis" events.
Definition: Zakero_Yetani.h:10200
zakero::Yetani::Window::setTitle
void setTitle(const std::string &) noexcept
Change the window title.
Definition: Zakero_Yetani.h:8901
zakero::Yetani::Window::setClass
void setClass(const std::string &) noexcept
Change the window class.
Definition: Zakero_Yetani.h:8888
zakero::Yetani::Output::height
int32_t height
The height of the device in hardware units.
Definition: Zakero_Yetani.h:1220
zakero::Yetani::shmFormatDescription
static std::string shmFormatDescription(const wl_shm_format) noexcept
Get a description of the format.
Definition: Zakero_Yetani.h:4415
zakero::Yetani::PointerButton
Information about a pointer button event.
Definition: Zakero_Yetani.h:1146
zakero::Yetani::outputVector
Yetani::VectorOutputId outputVector() const noexcept
Get a list of the Output Id's.
Definition: Zakero_Yetani.h:4714
zakero::Yetani::keyRepeatDelay
int32_t keyRepeatDelay() const noexcept
The key repeat delay.
Definition: Zakero_Yetani.h:5425
zakero::Yetani::LambdaSizePixel
std::function< void(const Yetani::SizePixel &)> LambdaSizePixel
A Lambda that has a parameter: SizePixel.
Definition: Zakero_Yetani.h:1324
Zakero_Base.h
Zakero Base.
zakero::Yetani::PointPercent
A location that uses percentages.
Definition: Zakero_Yetani.h:1094
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:1311
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:1318
zakero::Yetani::PointerAxis::steps
int32_t steps
The number of rotation steps.
Definition: Zakero_Yetani.h:1131
zakero::Yetani::keyRepeatRate
int32_t keyRepeatRate() const noexcept
The key repeat rate.
Definition: Zakero_Yetani.h:5439
zakero::Yetani::SizeMm::height
float height
The height.
Definition: Zakero_Yetani.h:1157
zakero::Yetani::Output::pixels_per_mm_horizontal
float pixels_per_mm_horizontal
A pre-calculated value.
Definition: Zakero_Yetani.h:1228
zakero::Yetani::Window::~Window
virtual ~Window()
Destroy a Window.
Definition: Zakero_Yetani.h:8791
zakero::Yetani::Output::subpixel
int32_t subpixel
The device's subpixel orientation.
Definition: Zakero_Yetani.h:1223
zakero::Yetani::CursorConfig
Cursor configuration.
Definition: Zakero_Yetani.h:1190
zakero::MemoryPool
A pool of memory.
Definition: Zakero_MemoryPool.h:264
zakero::Yetani::SizeMm::width
float width
The width.
Definition: Zakero_Yetani.h:1156
zakero::Yetani::WindowMode::Fullscreen
@ Fullscreen
A window that uses the entire screen, no borders.
zakero::Yetani::outputConvertToPercent
Yetani::PointPercent outputConvertToPercent(const Yetani::OutputId, const Yetani::PointPixel &) const noexcept
Convert Pixel to a Percentage.
Definition: Zakero_Yetani.h:4819
zakero::Yetani::SizeMm
Size measured in millimeters.
Definition: Zakero_Yetani.h:1155
zakero::Yetani::Output::model
std::string model
Description of the model.
Definition: Zakero_Yetani.h:1216
zakero::Yetani::PointerAxisType
PointerAxisType
The direction of the axis movement.
Definition: Zakero_Yetani.h:1123
zakero::Yetani::Output::physical_height_mm
int32_t physical_height_mm
The height of the device in millimeters.
Definition: Zakero_Yetani.h:1222
zakero::Yetani::Output::scale_factor
int32_t scale_factor
The scaling factor between the device and compositor.
Definition: Zakero_Yetani.h:1225
zakero::Yetani::Key::time
uint32_t time
When the key event happened.
Definition: Zakero_Yetani.h:1062
zakero::Yetani::PointPercent::time
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1095
zakero::Yetani::Output::y
int32_t y
The Y position within the global compositor.
Definition: Zakero_Yetani.h:1218
zakero::Yetani::Window::cursorHide
void cursorHide() noexcept
Hide the cursor.
Definition: Zakero_Yetani.h:8853
zakero::Yetani::Window::onCloseRequest
void onCloseRequest(Yetani::Lambda) noexcept
Respond to "Close Request" events.
Definition: Zakero_Yetani.h:9646
zakero::Yetani::output
Yetani::Output output(const Yetani::OutputId) const noexcept
Get a copy of the Output information.
Definition: Zakero_Yetani.h:4682
zakero::MemoryPool::sizeOnChange
void sizeOnChange(MemoryPool::LambdaSize) noexcept
Set the Size Event callback.
Definition: Zakero_MemoryPool.h:770
zakero::Yetani::outputConvertToMm
Yetani::PointMm outputConvertToMm(const Yetani::OutputId, const Yetani::PointPixel &) const noexcept
Convert Pixel to Millimeter.
Definition: Zakero_Yetani.h:4789
zakero::Yetani::SizePercent::width
float width
The width.
Definition: Zakero_Yetani.h:1164
zakero::Yetani::Window::Window
Window(void *)
Construct a Window.
Definition: Zakero_Yetani.h:8737
zakero::Yetani::outputSubpixelName
static std::string outputSubpixelName(int32_t) noexcept
Get a human readable string.
Definition: Zakero_Yetani.h:4740
zakero::Yetani::Output::x
int32_t x
The X position within the global compositor.
Definition: Zakero_Yetani.h:1217
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:1312
zakero::Yetani::shmFormatName
static std::string shmFormatName(const wl_shm_format) noexcept
Get the name of the format.
Definition: Zakero_Yetani.h:4438
zakero::Yetani::Window::windowMode
Yetani::WindowMode windowMode() noexcept
Get the current WindowMode.
Definition: Zakero_Yetani.h:8955
zakero::Yetani::WindowMode::Maximized
@ Maximized
A window that uses as much of the screen as possible.
zakero::Yetani::Output::width
int32_t width
The width of the device in hardware units.
Definition: Zakero_Yetani.h:1219
zakero::Yetani::Window::cursorShow
void cursorShow() noexcept
Show the cursor.
Definition: Zakero_Yetani.h:8864
zakero::Yetani::Output::flags
uint32_t flags
Device flags.
Definition: Zakero_Yetani.h:1227
zakero::Yetani::PointPixel::y
int32_t y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1106
zakero::Yetani::Window::windowModeIs
bool windowModeIs(const Yetani::WindowMode) noexcept
Check the WindowMode.
Definition: Zakero_Yetani.h:8973
zakero::Yetani::KeyModifier::locked
uint32_t locked
A collection of locked modifiers.
Definition: Zakero_Yetani.h:1077
zakero::MemoryPool::fd
int fd() const noexcept
The backing file descriptor.
Definition: Zakero_MemoryPool.h:722
zakero::Yetani::Window::keyboardOnLeave
void keyboardOnLeave(Yetani::Lambda) noexcept
Respond to "Keyboard Leave" events.
Definition: Zakero_Yetani.h:9747
zakero::Yetani::LambdaBool
std::function< void(bool)> LambdaBool
A Lambda that has a parameter: bool.
Definition: Zakero_Yetani.h:1319
zakero::Yetani::SizePercent::height
float height
The height.
Definition: Zakero_Yetani.h:1165
zakero::Yetani::Window::windowModeSet
void windowModeSet(const Yetani::WindowMode) noexcept
Change the window mode.
Definition: Zakero_Yetani.h:8997
zakero::Yetani::KeyModifier
A collection modifier flags.
Definition: Zakero_Yetani.h:1074
zakero::Yetani::PointerButton::code
uint32_t code
The event code.
Definition: Zakero_Yetani.h:1147
zakero::Yetani::Window::imageNext
std::error_code imageNext(uint8_t *&, Yetani::SizePixel &) noexcept
Get an image buffer.
Definition: Zakero_Yetani.h:9342
zakero::Yetani::WindowDecorations
WindowDecorations
Who is responsible for rendering the decorations.
Definition: Zakero_Yetani.h:1298
zakero::Yetani::outputOnChange
void outputOnChange(Yetani::LambdaOutputId) noexcept
Notification that an Output device has changed.
Definition: Zakero_Yetani.h:5049
zakero::Yetani::PointerAxisSource::Wheel_Tilt
@ Wheel_Tilt
Wheel Tilt.
zakero::Yetani::Key
Key event information.
Definition: Zakero_Yetani.h:1061
zakero::Yetani::Window::convertToPixel
Yetani::PointPixel convertToPixel(const Yetani::PointMm &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9502
zakero::Yetani::Window::keyboardOnKey
void keyboardOnKey(Yetani::LambdaKey) noexcept
Respond to "Keyboard Key" events.
Definition: Zakero_Yetani.h:9775
zakero::Yetani::KeyState::Released
@ Released
Released.
zakero::Yetani::cursorDestroy
std::error_code cursorDestroy(const std::string &) noexcept
Destroy a cursor.
Definition: Zakero_Yetani.h:3886
zakero::Yetani::KeyModifier_Shift
static constexpr uint32_t KeyModifier_Shift
Key Modifier flag.
Definition: Zakero_Yetani.h:1071
zakero::Yetani::LambdaSizePercent
std::function< void(const Yetani::SizePercent &)> LambdaSizePercent
A Lambda that has a parameter: SizePercent.
Definition: Zakero_Yetani.h:1323
zakero::Yetani::WindowMode::Normal
@ Normal
A normal window.
zakero::Yetani::PointMm::time
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1086
zakero::Yetani::PointPixel::x
int32_t x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1105
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:1316
zakero::Yetani::PointerButtonState
PointerButtonState
Mouse button state.
Definition: Zakero_Yetani.h:1141
zakero::Yetani::KeyModifier_CapsLock
static constexpr uint32_t KeyModifier_CapsLock
Key Modifier flag.
Definition: Zakero_Yetani.h:1068
zakero::Yetani::Window::pointerOnLeave
void pointerOnLeave(Yetani::Lambda) noexcept
Respond to "Pointer Leave" events.
Definition: Zakero_Yetani.h:10089
zakero::Yetani::SizeMm::operator==
friend bool operator==(Yetani::SizeMm &, Yetani::SizeMm &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10611
zakero::Yetani::KeyModifier::latched
uint32_t latched
A collection of latched modifiers.
Definition: Zakero_Yetani.h:1076
zakero::Yetani::shmFormatAvailable
const Yetani::VectorShmFormat & shmFormatAvailable() const noexcept
Get all the support color formats.
Definition: Zakero_Yetani.h:4373
zakero::Yetani::KeyModifier_Meta
static constexpr uint32_t KeyModifier_Meta
Key Modifier flag.
Definition: Zakero_Yetani.h:1070
zakero::Yetani::Window::cursorUse
std::error_code cursorUse(const std::string &) noexcept
Use a cursor.
Definition: Zakero_Yetani.h:8836
zakero::Yetani::shmFormatBytesPerPixel
static uint8_t shmFormatBytesPerPixel(const wl_shm_format) noexcept
Determine bytes-per-pixel.
Definition: Zakero_Yetani.h:4390
zakero::Yetani::KeyState
KeyState
Keyboard key state
Definition: Zakero_Yetani.h:1055
zakero::Yetani::PointPercent::operator==
friend bool operator==(Yetani::PointPercent &, Yetani::PointPercent &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10572
zakero::Yetani::WindowDecorations::Client_Side
@ Client_Side
The user app must draw the decorations.
zakero::Yetani::PointerAxis::distance
float distance
The distance traveled.
Definition: Zakero_Yetani.h:1132
zakero::Yetani::PointerAxis::source
Yetani::PointerAxisSource source
The source of the event.
Definition: Zakero_Yetani.h:1133
zakero::Yetani::Window::convertToMm
Yetani::PointMm convertToMm(const Yetani::PointPixel &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9456
zakero::Yetani::Output::refresh_mHz
int32_t refresh_mHz
The current refresh rate of the device.
Definition: Zakero_Yetani.h:1224
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:4765
zakero::Yetani::PointerAxisSource::Continuous
@ Continuous
Continuous.
zakero::Yetani::WindowDecorations::Server_Side
@ Server_Side
The Wayland Compositor will draw the decorations.
zakero::Yetani::PointPixel::operator==
friend bool operator==(Yetani::PointPixel &, Yetani::PointPixel &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10592
zakero::Yetani::PointerAxisSource
PointerAxisSource
Where the axis information came from.
Definition: Zakero_Yetani.h:1115
zakero::Yetani::PointPercent::y
float y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1097
zakero::Yetani::PointPercent::x
float x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1096
zakero::Yetani::PointMm
A location that uses millimeters.
Definition: Zakero_Yetani.h:1085
zakero::Yetani::Window::onFocusChange
void onFocusChange(Yetani::LambdaBool) noexcept
Respond to "Active" change events.
Definition: Zakero_Yetani.h:9700
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:1315
zakero::Yetani::Window::pointerOnAxisDiscrete
void pointerOnAxisDiscrete(Yetani::Lambda) noexcept
Respond to "Pointer Axis Discrete" events.
Definition: Zakero_Yetani.h:10281
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:1069
zakero::Yetani::Window::pointerOnMotion
void pointerOnMotion(Yetani::LambdaPointMm) noexcept
Respond to "Pointer Motion" events.
Definition: Zakero_Yetani.h:10117
zakero::Yetani::windowCreate
Yetani::Window * windowCreate(const Yetani::SizeMm &, std::error_code &) noexcept
Create a window.
Definition: Zakero_Yetani.h:8001
zakero::Yetani::LambdaSizeMm
std::function< void(const Yetani::SizeMm &)> LambdaSizeMm
A Lambda that has a parameter: SizeMm.
Definition: Zakero_Yetani.h:1322
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:1314
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:628
zakero::Yetani::Output::physical_width_mm
int32_t physical_width_mm
The width of the device in millimeters.
Definition: Zakero_Yetani.h:1221
zakero::Yetani::PointMm::x
float x
Where in the X-Axis the point is.
Definition: Zakero_Yetani.h:1087
zakero::Yetani::SizePercent::operator==
friend bool operator==(Yetani::SizePercent &, Yetani::SizePercent &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10632
zakero::Yetani::Window::onDecorationsChange
void onDecorationsChange(Yetani::LambdaWindowDecorations) noexcept
Respond to "Decoration Change" events.
Definition: Zakero_Yetani.h:9671
zakero::Yetani::PointMm::y
float y
Where in the Y-Axis the point is.
Definition: Zakero_Yetani.h:1088
zakero::Yetani::connect
static Yetani * connect() noexcept
Establish a connection with the Wayland Compositor.
Definition: Zakero_Yetani.h:3264
zakero::Yetani::PointerAxisType::Vertical
@ Vertical
Vertical.
zakero::Yetani::Key::code
uint32_t code
The key code of the event.
Definition: Zakero_Yetani.h:1063
zakero::Yetani::Lambda
std::function< void()> Lambda
A Lambda that has no parameters.
Definition: Zakero_Yetani.h:1310
zakero::Yetani::PointerAxis
Information about an Axis event.
Definition: Zakero_Yetani.h:1129
zakero::Yetani::cursorCreate
std::error_code cursorCreate(const std::string &, const Yetani::CursorConfig &) noexcept
Create a cursor.
Definition: Zakero_Yetani.h:3747
zakero::Yetani::PointPixel
A location that uses pixels.
Definition: Zakero_Yetani.h:1103
zakero::Yetani::KeyModifier::pressed
uint32_t pressed
A collection of pressed modifiers.
Definition: Zakero_Yetani.h:1075
zakero::Yetani::PointerAxisSource::Finger
@ Finger
Finger.
zakero::Yetani::Window::pointerOnAxisStop
void pointerOnAxisStop(Yetani::Lambda) noexcept
Respond to "Pointer Axis Stop" events.
Definition: Zakero_Yetani.h:10254
zakero::Yetani::Output::pixels_per_mm_vertical
float pixels_per_mm_vertical
A pre-calculated value.
Definition: Zakero_Yetani.h:1229
zakero::Yetani::Output::transform
int32_t transform
Transform that maps framebuffer to output.
Definition: Zakero_Yetani.h:1226
zakero::Yetani::Window::keyboardOnEnter
void keyboardOnEnter(Yetani::Lambda) noexcept
Respond to "Keyboard Enter" events.
Definition: Zakero_Yetani.h:9721
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:1313
zakero::Yetani
A wrapper class for Wayland.
Definition: Zakero_Yetani.h:1030
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::SizePixel::width
int32_t width
The width.
Definition: Zakero_Yetani.h:1172
zakero::operator==
bool operator==(Yetani::PointMm &lhs, Yetani::PointMm &rhs) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10549
zakero::Yetani::Window::convertToPercent
Yetani::PointPercent convertToPercent(const Yetani::PointPixel &) const noexcept
Unit conversion.
Definition: Zakero_Yetani.h:9479
zakero::Yetani::Window::onSizeChange
void onSizeChange(Yetani::LambdaSizeMm) noexcept
Respond to "Resize" events.
Definition: Zakero_Yetani.h:9831
zakero::Yetani::PointMm::operator==
friend bool operator==(Yetani::PointMm &, Yetani::PointMm &) noexcept
Compare two Point objects.
Definition: Zakero_Yetani.h:10549
zakero::Yetani::outputOnRemove
void outputOnRemove(Yetani::LambdaOutputId) noexcept
Notification of removing an Output device.
Definition: Zakero_Yetani.h:5072
zakero::Yetani::PointerButton::state
Yetani::PointerButtonState state
The button state.
Definition: Zakero_Yetani.h:1148
zakero::Yetani::PointerAxisType::Horizontal
@ Horizontal
Horizontal.
zakero::Yetani::KeyState::Pressed
@ Pressed
Pressed.
zakero::to_string
std::string to_string(const wl_shm_format) noexcept
Convert a value to a std::string.
Definition: Zakero_Yetani.h:10334
zakero::Yetani::Window::setDecorations
std::error_code setDecorations(const Yetani::WindowDecorations) noexcept
Use the Desktop Environment borders.
Definition: Zakero_Yetani.h:8927
zakero::Yetani::KeyModifier_Alt
static constexpr uint32_t KeyModifier_Alt
Key Modifier flag.
Definition: Zakero_Yetani.h:1067
zakero::Yetani::Window::time
uint32_t time() const noexcept
When the last frame was rendered.
Definition: Zakero_Yetani.h:9410
zakero::Yetani::Window::minimize
void minimize() noexcept
Minimize the window.
Definition: Zakero_Yetani.h:9441
zakero::Yetani::Window
A Window.
Definition: Zakero_Yetani.h:1329
zakero::Yetani::SizePixel
Size measured in pixels.
Definition: Zakero_Yetani.h:1171
zakero::Yetani::Key::state
KeyState state
The state of the key.
Definition: Zakero_Yetani.h:1064
zakero::Yetani::Window::setSizeMinMax
std::error_code setSizeMinMax(const Yetani::SizeMm &, const Yetani::SizeMm &) noexcept
Set the minimum window size.
Definition: Zakero_Yetani.h:9181
zakero::Yetani::Output
Information about a output device.
Definition: Zakero_Yetani.h:1214
zakero::Yetani::Window::setSize
std::error_code setSize(const Yetani::SizeMm &) noexcept
Set the window size.
Definition: Zakero_Yetani.h:9043
zakero::Yetani::PointerAxisSource::Wheel
@ Wheel
Wheel.
zakero::Yetani::Window::pointerOnButton
void pointerOnButton(Yetani::LambdaButtonMm) noexcept
Respond to "Pointer Button" events.
Definition: Zakero_Yetani.h:9912
zakero::Yetani::WindowMode
WindowMode
Definition: Zakero_Yetani.h:1303
zakero::Yetani::SHM_FORMAT_DEFAULT
static constexpr wl_shm_format SHM_FORMAT_DEFAULT
The default pixel format.
Definition: Zakero_Yetani.h:1441
zakero::Yetani::KeyModifier::group
uint32_t group
The keyboard layout.
Definition: Zakero_Yetani.h:1078
zakero::Yetani::Window::pointerOnEnter
void pointerOnEnter(Yetani::LambdaPointMm) noexcept
Respond to "Pointer Enter" events.
Definition: Zakero_Yetani.h:9999
zakero::Yetani::Window::windowModeOnChange
void windowModeOnChange(Yetani::LambdaWindowMode) noexcept
Respond to "Window Mode" events.
Definition: Zakero_Yetani.h:9802
zakero::Yetani::PointPixel::time
uint32_t time
Where in time the point is (if > 0).
Definition: Zakero_Yetani.h:1104
zakero::Yetani::LambdaWindowDecorations
std::function< void(Yetani::WindowDecorations)> LambdaWindowDecorations
A Lambda that has a parameter: WindowDecorations.
Definition: Zakero_Yetani.h:1320
zakero::Yetani::~Yetani
virtual ZAKERO_YETANI__ERROR_DATA ~Yetani() noexcept
Destructor.
Definition: Zakero_Yetani.h:3228
zakero::Yetani::SizePercent
Size measured as a percentage of the Output (Monitor) resolution.
Definition: Zakero_Yetani.h:1163
zakero::Yetani::Window::pointerOnAxisSource
void pointerOnAxisSource(Yetani::Lambda) noexcept
Respond to "Pointer Axis Source" events.
Definition: Zakero_Yetani.h:10227
zakero::Yetani::Window::imagePresent
void imagePresent() noexcept
Render the image.
Definition: Zakero_Yetani.h:9378
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:1317
zakero::Yetani::Output::make
std::string make
Description of the manufacturer.
Definition: Zakero_Yetani.h:1215
zakero::Yetani::SizePixel::height
int32_t height
The height.
Definition: Zakero_Yetani.h:1173
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:1134
zakero::Yetani::Window::Memory
The shared memory.
Definition: Zakero_Yetani.h:1423
zakero::Yetani::Window::bytesPerPixel
uint8_t bytesPerPixel() const noexcept
Get the number of bytes per pixel.
Definition: Zakero_Yetani.h:9428
zakero::Yetani::outputOnAdd
void outputOnAdd(Yetani::LambdaOutputId) noexcept
Notification of adding an Output device.
Definition: Zakero_Yetani.h:5026
zakero::Yetani::LambdaWindowMode
std::function< void(Yetani::WindowMode)> LambdaWindowMode
A Lambda that has a parameter: WindowMode.
Definition: Zakero_Yetani.h:1321
zakero::Yetani::outputConvertToPixel
Yetani::PointPixel outputConvertToPixel(const Yetani::OutputId, const Yetani::PointMm &) const noexcept
Convert Millimeter to Pixel.
Definition: Zakero_Yetani.h:4849