#include "swayaway.h" #include #include #include #include #include #include "ext-idle-notify-v1-client-protocol.h" struct seat_entry { struct seat_entry *next; struct wl_seat *proxy; char *name; }; static struct seat_entry *seats; static struct ext_idle_notification_v1 *tracking; /* One tracking notification with timeout 0 is enough: the compositor sends * "idled" the moment the seat goes idle (a zero timeout means "as soon as * possible") and "resumed" when activity starts again, then restarts the * timer. All real timeout bookkeeping happens in idle.c against * CLOCK_MONOTONIC, so one protocol object per timeout is not needed. */ static void handle_idled(void *data, struct ext_idle_notification_v1 *notif) { (void)data; (void)notif; idle_on_idled(); } static void handle_resumed(void *data, struct ext_idle_notification_v1 *notif) { (void)data; (void)notif; idle_on_resumed(); } static const struct ext_idle_notification_v1_listener tracking_listener = { .idled = handle_idled, .resumed = handle_resumed, }; static void seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities) { (void)data; (void)seat; (void)capabilities; } static void seat_handle_name(void *data, struct wl_seat *seat, const char *name) { struct seat_entry *entry = data; (void)seat; if (name) { entry->name = strdup(name); } } static const struct wl_seat_listener seat_listener = { .capabilities = seat_handle_capabilities, .name = seat_handle_name, }; static void handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { (void)data; if (strcmp(interface, ext_idle_notifier_v1_interface.name) == 0) { state.notifier = wl_registry_bind(registry, name, &ext_idle_notifier_v1_interface, 1); sway_log_debug("bound ext_idle_notifier_v1 (version %u)", version); } else if (strcmp(interface, wl_seat_interface.name) == 0) { struct seat_entry *entry = calloc(1, sizeof(*entry)); if (!entry) { sway_log("out of memory binding seat"); return; } entry->proxy = wl_registry_bind(registry, name, &wl_seat_interface, 2); wl_seat_add_listener(entry->proxy, &seat_listener, entry); entry->next = seats; seats = entry; sway_log_debug("bound wl_seat"); } } static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { (void)data; (void)registry; (void)name; } static const struct wl_registry_listener registry_listener = { .global = handle_global, .global_remove = handle_global_remove, }; int wayland_init(void) { state.display = wl_display_connect(NULL); if (state.display == NULL) { sway_log("unable to connect to the compositor. " "Check or set WAYLAND_DISPLAY."); return -1; } struct wl_registry *registry = wl_display_get_registry(state.display); wl_registry_add_listener(registry, ®istry_listener, NULL); // roundtrip twice: once for globals, once for the seat name wl_display_roundtrip(state.display); wl_display_roundtrip(state.display); if (state.notifier == NULL) { sway_log("compositor does not support ext-idle-notify-v1"); return -1; } struct seat_entry *entry; for (entry = seats; entry; entry = entry->next) { if (state.seat_name == NULL || (entry->name && strcmp(entry->name, state.seat_name) == 0)) { state.seat = entry->proxy; break; } } if (state.seat == NULL) { if (state.seat_name) { sway_log("seat '%s' not found", state.seat_name); } else { sway_log("no seat found"); } return -1; } sway_log_debug("using seat '%s'", entry->name ? entry->name : "?"); return 0; } void wayland_create_tracking_notification(void) { if (state.notifier == NULL || state.seat == NULL || tracking != NULL) { return; } tracking = ext_idle_notifier_v1_get_idle_notification( state.notifier, 0, state.seat); ext_idle_notification_v1_add_listener(tracking, &tracking_listener, NULL); sway_log_debug("created tracking idle notification (timeout 0)"); wl_display_flush(state.display); }