1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <wayland-server-core.h>
5 #include <wlr/types/wlr_idle.h>
6 #include <wlr/util/log.h>
7 #include "idle-protocol.h"
8 #include "util/signal.h"
9
10 static const struct org_kde_kwin_idle_timeout_interface idle_timeout_impl;
11
idle_timeout_from_resource(struct wl_resource * resource)12 static struct wlr_idle_timeout *idle_timeout_from_resource(
13 struct wl_resource *resource) {
14 assert(wl_resource_instance_of(resource,
15 &org_kde_kwin_idle_timeout_interface, &idle_timeout_impl));
16 return wl_resource_get_user_data(resource);
17 }
18
idle_notify(void * data)19 static int idle_notify(void *data) {
20 struct wlr_idle_timeout *timer = data;
21 if (timer->idle_state) {
22 return 0;
23 }
24 timer->idle_state = true;
25 wlr_signal_emit_safe(&timer->events.idle, timer);
26
27 if (timer->resource) {
28 org_kde_kwin_idle_timeout_send_idle(timer->resource);
29 }
30 return 1;
31 }
32
handle_activity(struct wlr_idle_timeout * timer)33 static void handle_activity(struct wlr_idle_timeout *timer) {
34 if (!timer->enabled) {
35 return;
36 }
37
38 // in case the previous state was sleeping send a resume event and switch state
39 if (timer->idle_state) {
40 timer->idle_state = false;
41 wlr_signal_emit_safe(&timer->events.resume, timer);
42
43 if (timer->resource) {
44 org_kde_kwin_idle_timeout_send_resumed(timer->resource);
45 }
46 }
47
48 // rearm the timer
49 wl_event_source_timer_update(timer->idle_source, timer->timeout);
50 if (timer->timeout == 0) {
51 idle_notify(timer);
52 }
53 }
54
handle_timer_resource_destroy(struct wl_resource * timer_resource)55 static void handle_timer_resource_destroy(struct wl_resource *timer_resource) {
56 struct wlr_idle_timeout *timer = idle_timeout_from_resource(timer_resource);
57 if (timer != NULL) {
58 wlr_idle_timeout_destroy(timer);
59 }
60 }
61
handle_seat_destroy(struct wl_listener * listener,void * data)62 static void handle_seat_destroy(struct wl_listener *listener, void *data) {
63 struct wlr_idle_timeout *timer = wl_container_of(listener, timer, seat_destroy);
64 if (timer != NULL) {
65 wlr_idle_timeout_destroy(timer);
66 }
67 }
68
release_idle_timeout(struct wl_client * client,struct wl_resource * resource)69 static void release_idle_timeout(struct wl_client *client,
70 struct wl_resource *resource){
71 handle_timer_resource_destroy(resource);
72 }
73
simulate_activity(struct wl_client * client,struct wl_resource * resource)74 static void simulate_activity(struct wl_client *client,
75 struct wl_resource *resource){
76 struct wlr_idle_timeout *timer = idle_timeout_from_resource(resource);
77 handle_activity(timer);
78 }
79
80 static const struct org_kde_kwin_idle_timeout_interface idle_timeout_impl = {
81 .release = release_idle_timeout,
82 .simulate_user_activity = simulate_activity,
83 };
84
85 static const struct org_kde_kwin_idle_interface idle_impl;
86
idle_from_resource(struct wl_resource * resource)87 static struct wlr_idle *idle_from_resource(
88 struct wl_resource *resource) {
89 assert(wl_resource_instance_of(resource, &org_kde_kwin_idle_interface,
90 &idle_impl));
91 return wl_resource_get_user_data(resource);
92 }
93
handle_input_notification(struct wl_listener * listener,void * data)94 static void handle_input_notification(struct wl_listener *listener, void *data) {
95 struct wlr_idle_timeout *timer =
96 wl_container_of(listener, timer, input_listener);
97 struct wlr_seat *seat = data;
98 if (timer->seat == seat) {
99 handle_activity(timer);
100 }
101 }
102
create_timer(struct wlr_idle * idle,struct wlr_seat * seat,uint32_t timeout,struct wl_resource * resource)103 static struct wlr_idle_timeout *create_timer(struct wlr_idle *idle,
104 struct wlr_seat *seat, uint32_t timeout, struct wl_resource *resource) {
105 struct wlr_idle_timeout *timer =
106 calloc(1, sizeof(struct wlr_idle_timeout));
107 if (!timer) {
108 return NULL;
109 }
110
111 timer->seat = seat;
112 timer->timeout = timeout;
113 timer->idle_state = false;
114 timer->enabled = idle->enabled;
115
116 wl_list_insert(&idle->idle_timers, &timer->link);
117 wl_signal_init(&timer->events.idle);
118 wl_signal_init(&timer->events.resume);
119 wl_signal_init(&timer->events.destroy);
120
121 timer->seat_destroy.notify = handle_seat_destroy;
122 wl_signal_add(&timer->seat->events.destroy, &timer->seat_destroy);
123
124 timer->input_listener.notify = handle_input_notification;
125 wl_signal_add(&idle->events.activity_notify, &timer->input_listener);
126 // create the timer
127 timer->idle_source =
128 wl_event_loop_add_timer(idle->event_loop, idle_notify, timer);
129 if (timer->idle_source == NULL) {
130 wl_list_remove(&timer->link);
131 wl_list_remove(&timer->input_listener.link);
132 wl_list_remove(&timer->seat_destroy.link);
133 free(timer);
134 return NULL;
135 }
136
137 if (resource) {
138 timer->resource = resource;
139 wl_resource_set_user_data(resource, timer);
140 }
141
142 if (timer->enabled) {
143 // arm the timer
144 wl_event_source_timer_update(timer->idle_source, timer->timeout);
145 if (timer->timeout == 0) {
146 idle_notify(timer);
147 }
148 }
149
150 return timer;
151 }
152
create_idle_timer(struct wl_client * client,struct wl_resource * idle_resource,uint32_t id,struct wl_resource * seat_resource,uint32_t timeout)153 static void create_idle_timer(struct wl_client *client,
154 struct wl_resource *idle_resource, uint32_t id,
155 struct wl_resource *seat_resource, uint32_t timeout) {
156 struct wlr_idle *idle = idle_from_resource(idle_resource);
157 struct wlr_seat_client *client_seat =
158 wlr_seat_client_from_resource(seat_resource);
159
160 struct wl_resource *resource = wl_resource_create(client,
161 &org_kde_kwin_idle_timeout_interface,
162 wl_resource_get_version(idle_resource), id);
163 if (resource == NULL) {
164 wl_resource_post_no_memory(idle_resource);
165 return;
166 }
167 wl_resource_set_implementation(resource, &idle_timeout_impl,
168 NULL, handle_timer_resource_destroy);
169
170 if (!create_timer(idle, client_seat->seat, timeout, resource)) {
171 wl_resource_post_no_memory(resource);
172 }
173 }
174
175 static const struct org_kde_kwin_idle_interface idle_impl = {
176 .get_idle_timeout = create_idle_timer,
177 };
178
wlr_idle_set_enabled(struct wlr_idle * idle,struct wlr_seat * seat,bool enabled)179 void wlr_idle_set_enabled(struct wlr_idle *idle, struct wlr_seat *seat,
180 bool enabled) {
181 if (idle->enabled == enabled) {
182 return;
183 }
184 wlr_log(WLR_DEBUG, "%s idle timers for %s",
185 enabled ? "Enabling" : "Disabling",
186 seat ? seat->name : "all seats");
187 idle->enabled = enabled;
188 struct wlr_idle_timeout *timer;
189 wl_list_for_each(timer, &idle->idle_timers, link) {
190 if (seat != NULL && timer->seat != seat) {
191 continue;
192 }
193 int timeout = enabled ? timer->timeout : 0;
194 wl_event_source_timer_update(timer->idle_source, timeout);
195 timer->enabled = enabled;
196 }
197 }
198
idle_bind(struct wl_client * wl_client,void * data,uint32_t version,uint32_t id)199 static void idle_bind(struct wl_client *wl_client, void *data,
200 uint32_t version, uint32_t id) {
201 struct wlr_idle *idle = data;
202 assert(wl_client && idle);
203
204 struct wl_resource *wl_resource = wl_resource_create(wl_client,
205 &org_kde_kwin_idle_interface, version, id);
206 if (wl_resource == NULL) {
207 wl_client_post_no_memory(wl_client);
208 return;
209 }
210 wl_resource_set_implementation(wl_resource, &idle_impl, idle, NULL);
211 }
212
handle_display_destroy(struct wl_listener * listener,void * data)213 static void handle_display_destroy(struct wl_listener *listener, void *data) {
214 struct wlr_idle *idle = wl_container_of(listener, idle, display_destroy);
215 wlr_signal_emit_safe(&idle->events.destroy, idle);
216 wl_list_remove(&idle->display_destroy.link);
217 wl_global_destroy(idle->global);
218 free(idle);
219 }
220
wlr_idle_create(struct wl_display * display)221 struct wlr_idle *wlr_idle_create(struct wl_display *display) {
222 struct wlr_idle *idle = calloc(1, sizeof(struct wlr_idle));
223 if (!idle) {
224 return NULL;
225 }
226 wl_list_init(&idle->idle_timers);
227 wl_signal_init(&idle->events.activity_notify);
228 wl_signal_init(&idle->events.destroy);
229 idle->enabled = true;
230
231 idle->event_loop = wl_display_get_event_loop(display);
232 if (idle->event_loop == NULL) {
233 free(idle);
234 return NULL;
235 }
236
237 idle->display_destroy.notify = handle_display_destroy;
238 wl_display_add_destroy_listener(display, &idle->display_destroy);
239
240 idle->global = wl_global_create(display, &org_kde_kwin_idle_interface,
241 1, idle, idle_bind);
242 if (idle->global == NULL) {
243 wl_list_remove(&idle->display_destroy.link);
244 free(idle);
245 return NULL;
246 }
247 wlr_log(WLR_DEBUG, "idle manager created");
248 return idle;
249 }
250
wlr_idle_notify_activity(struct wlr_idle * idle,struct wlr_seat * seat)251 void wlr_idle_notify_activity(struct wlr_idle *idle, struct wlr_seat *seat) {
252 wlr_signal_emit_safe(&idle->events.activity_notify, seat);
253 }
254
wlr_idle_timeout_create(struct wlr_idle * idle,struct wlr_seat * seat,uint32_t timeout)255 struct wlr_idle_timeout *wlr_idle_timeout_create(struct wlr_idle *idle,
256 struct wlr_seat *seat, uint32_t timeout) {
257 return create_timer(idle, seat, timeout, NULL);
258 }
259
wlr_idle_timeout_destroy(struct wlr_idle_timeout * timer)260 void wlr_idle_timeout_destroy(struct wlr_idle_timeout *timer) {
261 wlr_signal_emit_safe(&timer->events.destroy, NULL);
262
263 wl_list_remove(&timer->input_listener.link);
264 wl_list_remove(&timer->seat_destroy.link);
265 wl_event_source_remove(timer->idle_source);
266 wl_list_remove(&timer->link);
267
268 if (timer->resource) {
269 wl_resource_set_user_data(timer->resource, NULL);
270 }
271
272 free(timer);
273 }
274