Add idle protocol

Signed-off-by: Heghedus Razvan <heghedus.razvan@gmail.com>
This commit is contained in:
Heghedus Razvan 2018-01-07 21:41:43 +02:00
parent 6834067ef5
commit 21cc5e6fef
5 changed files with 293 additions and 0 deletions

View file

@ -0,0 +1,51 @@
#ifndef WLR_TYPES_WLR_IDLE_H
#define WLR_TYPES_WLR_IDLE_H
#include <wayland-server.h>
#include <wlr/types/wlr_seat.h>
/**
* Idle protocol is used to create timers which will notify the client when the
* compositor does not receive any input for a given time(in milliseconds). Also
* the client will be notify when the timer receve an activity notify and already
* was in idle state. Besides this, the client is able to simulate user activity
* which will reset the timers and at any time can destroy the timer.
*/
struct wlr_idle {
struct wl_global *wl_global;
struct wl_list idle_timers; // wlr_idle_timeout::link
struct wl_event_loop *event_loop;
struct wl_listener display_destroy;
struct wl_signal activity_notify;
void *data;
};
struct wlr_idle_timeout {
struct wl_resource *resource;
struct wl_list link;
struct wlr_seat *seat;
struct wl_event_source *idle_source;
bool idle_state;
uint32_t timeout; // milliseconds
struct wl_listener input_listener;
struct wl_listener seat_destroy;
void *data;
};
struct wlr_idle *wlr_idle_create(struct wl_display *display);
void wlr_idle_destroy(struct wlr_idle *idle);
/**
* Send notification to restart all timers for the given seat. Called by
* compositor when there is an user activity event on that seat.
*/
void wlr_idle_notify_activity(struct wlr_idle *idle, struct wlr_seat *seat);
#endif

49
protocol/idle.xml Normal file
View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="idle">
<copyright><![CDATA[
Copyright (C) 2015 Martin Gräßlin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]></copyright>
<interface name="org_kde_kwin_idle" version="1">
<description summary="User idle time manager">
This interface allows to monitor user idle time on a given seat. The interface
allows to register timers which trigger after no user activity was registered
on the seat for a given interval. It notifies when user activity resumes.
This is useful for applications wanting to perform actions when the user is not
interacting with the system, e.g. chat applications setting the user as away, power
management features to dim screen, etc..
</description>
<request name="get_idle_timeout">
<arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/>
<arg name="seat" type="object" interface="wl_seat"/>
<arg name="timeout" type="uint" summary="The idle timeout in msec"/>
</request>
</interface>
<interface name="org_kde_kwin_idle_timeout" version="1">
<request name="release" type="destructor">
<description summary="release the timeout object"/>
</request>
<request name="simulate_user_activity">
<description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/>
</request>
<event name="idle">
<description summary="Triggered when there has not been any user activity in the requested idle time interval"/>
</event>
<event name="resumed">
<description summary="Triggered on the first user activity after an idle event"/>
</event>
</interface>
</protocol>

View file

@ -26,6 +26,7 @@ protocols = [
'gtk-primary-selection.xml', 'gtk-primary-selection.xml',
'screenshooter.xml', 'screenshooter.xml',
'server-decoration.xml', 'server-decoration.xml',
'idle.xml',
] ]
client_protocols = [ client_protocols = [
@ -34,6 +35,7 @@ client_protocols = [
'gtk-primary-selection.xml', 'gtk-primary-selection.xml',
'screenshooter.xml', 'screenshooter.xml',
'server-decoration.xml', 'server-decoration.xml',
'idle.xml',
] ]
wl_protos_src = [] wl_protos_src = []

View file

@ -6,6 +6,7 @@ lib_wlr_types = static_library(
'wlr_compositor.c', 'wlr_compositor.c',
'wlr_cursor.c', 'wlr_cursor.c',
'wlr_gamma_control.c', 'wlr_gamma_control.c',
'wlr_idle.c',
'wlr_input_device.c', 'wlr_input_device.c',
'wlr_keyboard.c', 'wlr_keyboard.c',
'wlr_list.c', 'wlr_list.c',

190
types/wlr_idle.c Normal file
View file

@ -0,0 +1,190 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-server.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/util/log.h>
#include "idle-protocol.h"
static void idle_timeout_destroy(struct wlr_idle_timeout *timer) {
wl_list_remove(&timer->input_listener.link);
wl_list_remove(&timer->seat_destroy.link);
wl_event_source_remove(timer->idle_source);
wl_list_remove(&timer->link);
wl_resource_set_user_data(timer->resource, NULL);
free(timer);
}
static int idle_notify(void *data) {
struct wlr_idle_timeout *timer = data;
timer->idle_state = true;
org_kde_kwin_idle_timeout_send_idle(timer->resource);
return 1;
}
static void handle_activity(struct wlr_idle_timeout *timer) {
// rearm the timer
wl_event_source_timer_update(timer->idle_source, timer->timeout);
// in case the previous state was sleeping send a resume event and switch state
if (timer->idle_state) {
timer->idle_state = false;
org_kde_kwin_idle_timeout_send_resumed(timer->resource);
}
}
static void handle_timer_resource_destroy(struct wl_resource *timer_resource) {
struct wlr_idle_timeout *timer = wl_resource_get_user_data(timer_resource);
if (timer != NULL) {
idle_timeout_destroy(timer);
}
}
static void handle_seat_destroy(struct wl_listener *listener, void *data) {
struct wlr_idle_timeout *timer = wl_container_of(listener, timer, seat_destroy);
if (timer != NULL) {
idle_timeout_destroy(timer);
}
}
static void release_idle_timeout(struct wl_client *client,
struct wl_resource *resource){
handle_timer_resource_destroy(resource);
}
static void simulate_activity(struct wl_client *client,
struct wl_resource *resource){
struct wlr_idle_timeout *timer = wl_resource_get_user_data(resource);
handle_activity(timer);
}
static struct org_kde_kwin_idle_timeout_interface idle_timeout_impl = {
.release = release_idle_timeout,
.simulate_user_activity = simulate_activity,
};
static void handle_input_notification(struct wl_listener *listener, void *data) {
struct wlr_idle_timeout *timer = wl_container_of(listener, timer, input_listener);
struct wlr_seat *seat = data;
if (timer->seat == seat) {
handle_activity(timer);
}
}
static void create_idle_timer(struct wl_client *client,
struct wl_resource *idle_resource,
uint32_t id,
struct wl_resource *seat_resource,
uint32_t timeout) {
struct wlr_idle *idle = wl_resource_get_user_data(idle_resource);
struct wlr_seat_client *client_seat =
wl_resource_get_user_data(seat_resource);
struct wlr_idle_timeout *timer =
calloc(1, sizeof(struct wlr_idle_timeout));
if (!timer) {
wl_resource_post_no_memory(idle_resource);
return;
}
timer->seat = client_seat->seat;
timer->timeout = timeout;
timer->idle_state = false;
timer->resource = wl_resource_create(client,
&org_kde_kwin_idle_timeout_interface,
wl_resource_get_version(idle_resource), id);
if (timer->resource == NULL) {
free(timer);
wl_resource_post_no_memory(idle_resource);
return;
}
wl_resource_set_implementation(timer->resource, &idle_timeout_impl, timer,
handle_timer_resource_destroy);
wl_list_insert(&idle->idle_timers, &timer->link);
timer->seat_destroy.notify = handle_seat_destroy;
wl_signal_add(&timer->seat->events.destroy, &timer->seat_destroy);
timer->input_listener.notify = handle_input_notification;
wl_signal_add(&idle->activity_notify, &timer->input_listener);
// create the timer
timer->idle_source =
wl_event_loop_add_timer(idle->event_loop, idle_notify, timer);
if (timer->idle_source == NULL) {
wl_list_remove(&timer->link);
wl_list_remove(&timer->input_listener.link);
wl_list_remove(&timer->seat_destroy.link);
wl_resource_set_user_data(timer->resource, NULL);
free(timer);
wl_resource_post_no_memory(idle_resource);
return;
}
// arm the timer
wl_event_source_timer_update(timer->idle_source, timer->timeout);
}
static struct org_kde_kwin_idle_interface idle_impl = {
.get_idle_timeout = create_idle_timer,
};
static void idle_bind(struct wl_client *wl_client, void *data,
uint32_t version, uint32_t id) {
struct wlr_idle *idle = data;
assert(wl_client && idle);
struct wl_resource *wl_resource = wl_resource_create(wl_client,
&org_kde_kwin_idle_interface, version, id);
if (wl_resource == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
wl_resource_set_implementation(wl_resource, &idle_impl, idle, NULL);
}
void wlr_idle_destroy(struct wlr_idle *idle) {
if (!idle) {
return;
}
wl_list_remove(&idle->display_destroy.link);
struct wlr_idle_timeout *timer, *tmp;
wl_list_for_each_safe(timer, tmp, &idle->idle_timers, link) {
idle_timeout_destroy(timer);
}
wl_global_destroy(idle->wl_global);
free(idle);
}
static void handle_display_destroy(struct wl_listener *listener, void *data) {
struct wlr_idle *idle = wl_container_of(listener, idle, display_destroy);
wlr_idle_destroy(idle);
}
struct wlr_idle *wlr_idle_create(struct wl_display *display) {
struct wlr_idle *idle = calloc(1, sizeof(struct wlr_idle));
if (!idle) {
return NULL;
}
wl_list_init(&idle->idle_timers);
wl_signal_init(&idle->activity_notify);
idle->event_loop = wl_display_get_event_loop(display);
if (idle->event_loop == NULL) {
free(idle);
return NULL;
}
idle->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &idle->display_destroy);
idle->wl_global = wl_global_create(display, &org_kde_kwin_idle_interface,
1, idle, idle_bind);
if (idle->wl_global == NULL){
wl_list_remove(&idle->display_destroy.link);
free(idle);
return NULL;
}
wlr_log(L_DEBUG, "idle manager created");
return idle;
}
void wlr_idle_notify_activity(struct wlr_idle *idle, struct wlr_seat *seat) {
wl_signal_emit(&idle->activity_notify, seat);
}