Merge pull request #556 from raazvvann/heghe/idle-protocol

Idle protocol
This commit is contained in:
Tony Crisci 2018-01-14 15:55:04 -05:00 committed by GitHub
commit e46d2dd0f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 520 additions and 0 deletions

189
examples/idle.c Normal file
View file

@ -0,0 +1,189 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <pthread.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <idle-client-protocol.h>
static struct org_kde_kwin_idle *idle_manager = NULL;
static struct wl_seat *seat = NULL;
static uint32_t timeout = 0, simulate_activity_timeout = 0, close_timeout = 0;
static int run = 1;
struct thread_args {
struct wl_display *display;
struct org_kde_kwin_idle_timeout *timer;
};
static void handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version) {
fprintf(stdout, "interfaces found: %s\n", interface);
if (strcmp(interface, "org_kde_kwin_idle") == 0) {
idle_manager = wl_registry_bind(registry, name, &org_kde_kwin_idle_interface, 1);
}
else if (strcmp(interface, "wl_seat") == 0) {
seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
}
}
static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) {
//TODO
}
static const struct wl_registry_listener registry_listener = {
.global = handle_global,
.global_remove = handle_global_remove,
};
static void handle_idle(void* data, struct org_kde_kwin_idle_timeout *timer) {
fprintf(stdout, "idle state\n");
}
static void handle_resume(void* data, struct org_kde_kwin_idle_timeout *timer) {
fprintf(stdout, "active state\n");
}
static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener = {
.idle = handle_idle,
.resumed = handle_resume,
};
int parse_args(int argc, char *argv[]) {
int c;
while ((c = getopt(argc, argv, "c:hs:t:")) != -1) {
switch(c)
{
case 'c':
close_timeout = strtoul(optarg, NULL, 10);
break;
case 's':
simulate_activity_timeout = strtoul(optarg, NULL, 10);
break;
case 't':
timeout = strtoul(optarg, NULL, 10);
break;
case 'h':
case '?':
printf("Usage: %s [OPTIONS]\n", argv[0]);
printf(" -t seconds\t\t\tidle timeout in seconds\n");
printf(" -s seconds optional\t\tsimulate user activity after x seconds\n");
printf(" -c seconds optional\t\tclose program after x seconds\n");
printf(" -h\t\t\t\tthis help menu\n");
return 1;
default:
return 1;
}
}
return 0;
}
void *simulate_activity(void *data) {
sleep(simulate_activity_timeout);
fprintf(stdout, "simulate user activity\n");
struct thread_args *arg = data;
org_kde_kwin_idle_timeout_simulate_user_activity(arg->timer);
wl_display_roundtrip(arg->display);
return NULL;
}
void *close_program(void *data) {
sleep(close_timeout);
struct thread_args *arg = data;
org_kde_kwin_idle_timeout_release(arg->timer);
wl_display_roundtrip(arg->display);
fprintf(stdout, "close program\n");
run = 0;
return NULL;
}
void *main_loop(void *data) {
struct wl_display *display = data;
while (wl_display_dispatch(display) != -1) {
;
}
return NULL;
}
int main(int argc, char *argv[]) {
if (parse_args(argc, argv) != 0) {
return -1;
}
if (timeout == 0) {
printf("idle timeout 0 is invalid\n");
return -1;
}
struct wl_display *display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "failed to create display\n");
return -1;
}
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (idle_manager == NULL) {
fprintf(stderr, "display doesn't support idle protocol\n");
return -1;
}
if (seat== NULL) {
fprintf(stderr, "seat error\n");
return -1;
}
struct org_kde_kwin_idle_timeout *timer =
org_kde_kwin_idle_get_idle_timeout(idle_manager, seat, timeout * 1000);
if (timer == NULL) {
fprintf(stderr, "Could not create idle_timeout\n");
return -1;
}
pthread_t t1, t2, t3;
struct thread_args arg = {
.timer = timer,
.display = display,
};
if (simulate_activity_timeout != 0 && simulate_activity_timeout < close_timeout) {
if (pthread_create(&t1, NULL, &simulate_activity, (void *)&arg) != 0) {
return -1;
}
}
if (close_timeout != 0) {
if (pthread_create(&t2, NULL, &close_program, (void *)&arg) != 0) {
if (simulate_activity_timeout != 0) {
pthread_cancel(t1);
}
return -1;
}
}
org_kde_kwin_idle_timeout_add_listener(timer, &idle_timer_listener, timer);
fprintf(stdout, "waiting\n");
if (pthread_create(&t3, NULL, &main_loop, (void *)display) != 0) {
if (simulate_activity_timeout != 0) {
pthread_cancel(t1);
}
if (close_timeout != 0 ) {
pthread_cancel(t2);
}
}
if (simulate_activity_timeout != 0) {
pthread_join(t1, NULL);
}
if (close_timeout != 0) {
pthread_join(t2, NULL);
}
pthread_cancel(t3);
wl_display_disconnect(display);
return 0;
}

View file

@ -5,6 +5,8 @@ lib_shared = static_library(
include_directories: include_directories('support')
)
threads = dependency('threads')
executable('simple', 'simple.c', dependencies: wlroots, link_with: lib_shared)
executable('pointer', 'pointer.c', dependencies: wlroots, link_with: lib_shared)
executable('touch', 'touch.c', dependencies: wlroots, link_with: lib_shared)
@ -32,3 +34,10 @@ executable(
dependencies: [wayland_client, wlr_protos, wlroots],
link_with: lib_shared,
)
executable(
'idle',
'idle.c',
dependencies: [wayland_client, wlr_protos, wlroots, threads],
link_with: lib_shared,
)

View file

@ -13,6 +13,7 @@
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_screenshooter.h>
#include <wlr/types/wlr_list.h>
#include <wlr/types/wlr_idle.h>
#include "rootston/view.h"
#include "rootston/config.h"
@ -44,6 +45,7 @@ struct roots_desktop {
struct wlr_screenshooter *screenshooter;
struct wlr_server_decoration_manager *server_decoration_manager;
struct wlr_primary_selection_device_manager *primary_selection_device_manager;
struct wlr_idle *idle;
struct wl_listener output_add;
struct wl_listener output_remove;

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',
'screenshooter.xml',
'server-decoration.xml',
'idle.xml',
]
client_protocols = [
@ -34,6 +35,7 @@ client_protocols = [
'gtk-primary-selection.xml',
'screenshooter.xml',
'server-decoration.xml',
'idle.xml',
]
wl_protos_src = []

View file

@ -8,6 +8,7 @@
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_gamma_control.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_output_layout.h>
@ -502,6 +503,7 @@ struct roots_desktop *desktop_create(struct roots_server *server,
WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT);
desktop->primary_selection_device_manager =
wlr_primary_selection_device_manager_create(server->wl_display);
desktop->idle = wlr_idle_create(server->wl_display);
return desktop;
}

View file

@ -5,6 +5,7 @@
#include <wlr/config.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/util/log.h>
#include <wlr/types/wlr_idle.h>
#include "rootston/xcursor.h"
#include "rootston/input.h"
#include "rootston/seat.h"
@ -14,6 +15,8 @@
static void handle_keyboard_key(struct wl_listener *listener, void *data) {
struct roots_keyboard *keyboard =
wl_container_of(listener, keyboard, keyboard_key);
struct roots_desktop *desktop = keyboard->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, keyboard->seat->seat);
struct wlr_event_keyboard_key *event = data;
roots_keyboard_handle_key(keyboard, event);
}
@ -22,12 +25,16 @@ static void handle_keyboard_modifiers(struct wl_listener *listener,
void *data) {
struct roots_keyboard *keyboard =
wl_container_of(listener, keyboard, keyboard_modifiers);
struct roots_desktop *desktop = keyboard->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, keyboard->seat->seat);
roots_keyboard_handle_modifiers(keyboard);
}
static void handle_cursor_motion(struct wl_listener *listener, void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, motion);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_event_pointer_motion *event = data;
roots_cursor_handle_motion(cursor, event);
}
@ -36,6 +43,8 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener,
void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, motion_absolute);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_event_pointer_motion_absolute *event = data;
roots_cursor_handle_motion_absolute(cursor, event);
}
@ -43,6 +52,8 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener,
static void handle_cursor_button(struct wl_listener *listener, void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, button);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_event_pointer_button *event = data;
roots_cursor_handle_button(cursor, event);
}
@ -50,6 +61,8 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {
static void handle_cursor_axis(struct wl_listener *listener, void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, axis);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_event_pointer_axis *event = data;
roots_cursor_handle_axis(cursor, event);
}
@ -57,6 +70,8 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) {
static void handle_touch_down(struct wl_listener *listener, void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, touch_down);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_event_touch_down *event = data;
roots_cursor_handle_touch_down(cursor, event);
}
@ -64,6 +79,8 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
static void handle_touch_up(struct wl_listener *listener, void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, touch_up);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_event_touch_up *event = data;
roots_cursor_handle_touch_up(cursor, event);
}
@ -71,6 +88,8 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
static void handle_touch_motion(struct wl_listener *listener, void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, touch_motion);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_event_touch_motion *event = data;
roots_cursor_handle_touch_motion(cursor, event);
}
@ -78,6 +97,8 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
static void handle_tool_axis(struct wl_listener *listener, void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, tool_axis);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_event_tablet_tool_axis *event = data;
roots_cursor_handle_tool_axis(cursor, event);
}
@ -85,6 +106,8 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) {
static void handle_tool_tip(struct wl_listener *listener, void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, tool_tip);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_event_tablet_tool_tip *event = data;
roots_cursor_handle_tool_tip(cursor, event);
}
@ -93,6 +116,8 @@ static void handle_request_set_cursor(struct wl_listener *listener,
void *data) {
struct roots_cursor *cursor =
wl_container_of(listener, cursor, request_set_cursor);
struct roots_desktop *desktop = cursor->seat->input->server->desktop;
wlr_idle_notify_activity(desktop->idle, cursor->seat->seat);
struct wlr_seat_pointer_request_set_cursor_event *event = data;
roots_cursor_handle_request_set_cursor(cursor, event);
}

View file

@ -6,6 +6,7 @@ lib_wlr_types = static_library(
'wlr_compositor.c',
'wlr_cursor.c',
'wlr_gamma_control.c',
'wlr_idle.c',
'wlr_input_device.c',
'wlr_keyboard.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);
}