swayaway
a drop-in replacement for swayidle(1)
wayland.c
4275 bytes raw
1#include "swayaway.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7#include <wayland-client.h>
8#include "ext-idle-notify-v1-client-protocol.h"
9
10struct seat_entry {
11 struct seat_entry *next;
12 struct wl_seat *proxy;
13 char *name;
14};
15
16static struct seat_entry *seats;
17static struct ext_idle_notification_v1 *tracking;
18
19/* One tracking notification with timeout 0 is enough: the compositor sends
20 * "idled" the moment the seat goes idle (a zero timeout means "as soon as
21 * possible") and "resumed" when activity starts again, then restarts the
22 * timer. All real timeout bookkeeping happens in idle.c against
23 * CLOCK_MONOTONIC, so one protocol object per timeout is not needed. */
24
25static void handle_idled(void *data, struct ext_idle_notification_v1 *notif)
26{
27 (void)data;
28 (void)notif;
29 idle_on_idled();
30}
31
32static void handle_resumed(void *data, struct ext_idle_notification_v1 *notif)
33{
34 (void)data;
35 (void)notif;
36 idle_on_resumed();
37}
38
39static const struct ext_idle_notification_v1_listener tracking_listener = {
40 .idled = handle_idled,
41 .resumed = handle_resumed,
42};
43
44static void seat_handle_capabilities(void *data, struct wl_seat *seat,
45 uint32_t capabilities)
46{
47 (void)data;
48 (void)seat;
49 (void)capabilities;
50}
51
52static void seat_handle_name(void *data, struct wl_seat *seat,
53 const char *name)
54{
55 struct seat_entry *entry = data;
56 (void)seat;
57 if (name) {
58 entry->name = strdup(name);
59 }
60}
61
62static const struct wl_seat_listener seat_listener = {
63 .capabilities = seat_handle_capabilities,
64 .name = seat_handle_name,
65};
66
67static void handle_global(void *data, struct wl_registry *registry,
68 uint32_t name, const char *interface, uint32_t version)
69{
70 (void)data;
71 if (strcmp(interface, ext_idle_notifier_v1_interface.name) == 0) {
72 state.notifier = wl_registry_bind(registry, name,
73 &ext_idle_notifier_v1_interface, 1);
74 sway_log_debug("bound ext_idle_notifier_v1 (version %u)", version);
75 } else if (strcmp(interface, wl_seat_interface.name) == 0) {
76 struct seat_entry *entry = calloc(1, sizeof(*entry));
77 if (!entry) {
78 sway_log("out of memory binding seat");
79 return;
80 }
81 entry->proxy = wl_registry_bind(registry, name, &wl_seat_interface, 2);
82 wl_seat_add_listener(entry->proxy, &seat_listener, entry);
83 entry->next = seats;
84 seats = entry;
85 sway_log_debug("bound wl_seat");
86 }
87}
88
89static void handle_global_remove(void *data, struct wl_registry *registry,
90 uint32_t name)
91{
92 (void)data;
93 (void)registry;
94 (void)name;
95}
96
97static const struct wl_registry_listener registry_listener = {
98 .global = handle_global,
99 .global_remove = handle_global_remove,
100};
101
102int wayland_init(void)
103{
104 state.display = wl_display_connect(NULL);
105 if (state.display == NULL) {
106 sway_log("unable to connect to the compositor. "
107 "Check or set WAYLAND_DISPLAY.");
108 return -1;
109 }
110
111 struct wl_registry *registry = wl_display_get_registry(state.display);
112 wl_registry_add_listener(registry, ®istry_listener, NULL);
113 // roundtrip twice: once for globals, once for the seat name
114 wl_display_roundtrip(state.display);
115 wl_display_roundtrip(state.display);
116
117 if (state.notifier == NULL) {
118 sway_log("compositor does not support ext-idle-notify-v1");
119 return -1;
120 }
121
122 struct seat_entry *entry;
123 for (entry = seats; entry; entry = entry->next) {
124 if (state.seat_name == NULL ||
125 (entry->name && strcmp(entry->name, state.seat_name) == 0)) {
126 state.seat = entry->proxy;
127 break;
128 }
129 }
130
131 if (state.seat == NULL) {
132 if (state.seat_name) {
133 sway_log("seat '%s' not found", state.seat_name);
134 } else {
135 sway_log("no seat found");
136 }
137 return -1;
138 }
139 sway_log_debug("using seat '%s'",
140 entry->name ? entry->name : "?");
141 return 0;
142}
143
144void wayland_create_tracking_notification(void)
145{
146 if (state.notifier == NULL || state.seat == NULL || tracking != NULL) {
147 return;
148 }
149 tracking = ext_idle_notifier_v1_get_idle_notification(
150 state.notifier, 0, state.seat);
151 ext_idle_notification_v1_add_listener(tracking, &tracking_listener, NULL);
152 sway_log_debug("created tracking idle notification (timeout 0)");
153 wl_display_flush(state.display);
154}