Skip to content

Commit

Permalink
idle: support ext-idle-notify-v1 protocol
Browse files Browse the repository at this point in the history
wlroots no longer supports the old KDE one, so this is necessary. Keep
the old one around for now.
  • Loading branch information
r-c-f committed Mar 6, 2024
1 parent 5e678a1 commit 5bd3307
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 2 deletions.
5 changes: 4 additions & 1 deletion include/wayland.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "virtual-keyboard-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "idle-client-protocol.h"
#include "ext-idle-notify-v1-client-protocol.h"
#include "uSynergy.h"


Expand Down Expand Up @@ -49,6 +50,7 @@ struct wlIdle
void (*inhibit_stop)(struct wlIdle *);
};

extern bool wlIdleInitExt(struct wlContext *ctx);
extern bool wlIdleInitKde(struct wlContext *ctx);
extern bool wlIdleInitGnome(struct wlContext *ctx);

Expand Down Expand Up @@ -113,7 +115,8 @@ struct wlContext {
struct zxdg_output_manager_v1 *output_manager;
struct wlOutput *outputs;
/* idle stuff */
struct org_kde_kwin_idle *idle_manager;
struct org_kde_kwin_idle *idle_manager; /* old KDE */
struct ext_idle_notifier_v1 *idle_notifier; /* new standard */
struct wlIdle idle;
//state
int width;
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ src_c = files(
'src/wl_idle.c',
'src/wl_idle_gnome.c',
'src/wl_idle_kde.c',
'src/wl_idle_ext.c',
'src/wl_input.c',
'src/wl_input_wlr.c',
'src/wl_input_kde.c',
Expand Down
102 changes: 102 additions & 0 deletions protocol/ext-idle-notify-v1.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="ext_idle_notify_v1">
<copyright>
Copyright © 2015 Martin Gräßlin
Copyright © 2022 Simon Ser

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>

<interface name="ext_idle_notifier_v1" version="1">
<description summary="idle notification manager">
This interface allows clients to monitor user idle status.

After binding to this global, clients can create ext_idle_notification_v1
objects to get notified when the user is idle for a given amount of time.
</description>

<request name="destroy" type="destructor">
<description summary="destroy the manager">
Destroy the manager object. All objects created via this interface
remain valid.
</description>
</request>

<request name="get_idle_notification">
<description summary="create a notification object">
Create a new idle notification object.

The notification object has a minimum timeout duration and is tied to a
seat. The client will be notified if the seat is inactive for at least
the provided timeout. See ext_idle_notification_v1 for more details.

A zero timeout is valid and means the client wants to be notified as
soon as possible when the seat is inactive.
</description>
<arg name="id" type="new_id" interface="ext_idle_notification_v1"/>
<arg name="timeout" type="uint" summary="minimum idle timeout in msec"/>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
</interface>

<interface name="ext_idle_notification_v1" version="1">
<description summary="idle notification">
This interface is used by the compositor to send idle notification events
to clients.

Initially the notification object is not idle. The notification object
becomes idle when no user activity has happened for at least the timeout
duration, starting from the creation of the notification object. User
activity may include input events or a presence sensor, but is
compositor-specific. If an idle inhibitor is active (e.g. another client
has created a zwp_idle_inhibitor_v1 on a visible surface), the compositor
must not make the notification object idle.

When the notification object becomes idle, an idled event is sent. When
user activity starts again, the notification object stops being idle,
a resumed event is sent and the timeout is restarted.
</description>

<request name="destroy" type="destructor">
<description summary="destroy the notification object">
Destroy the notification object.
</description>
</request>

<event name="idled">
<description summary="notification object is idle">
This event is sent when the notification object becomes idle.

It's a compositor protocol error to send this event twice without a
resumed event in-between.
</description>
</event>

<event name="resumed">
<description summary="notification object is no longer idle">
This event is sent when the notification object stops being idle.

It's a compositor protocol error to send this event twice without an
idled event in-between. It's a compositor protocol error to send this
event prior to any idled event.
</description>
</event>
</interface>
</protocol>
1 change: 1 addition & 0 deletions protocol/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ wayland_scanner_client = generator(

client_protocols = [
['idle.xml'],
['ext-idle-notify-v1.xml'],
['fake-input.xml'],
['keyboard-shortcuts-inhibit-unstable-v1.xml'],
['virtual-keyboard-unstable-v1.xml'],
Expand Down
7 changes: 6 additions & 1 deletion src/wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,9 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
} else if (strcmp(interface, org_kde_kwin_idle_interface.name) == 0) {
logDbg("Got idle manager");
ctx->idle_manager = wl_registry_bind(registry, name, &org_kde_kwin_idle_interface, version);
} else if (strcmp(interface, ext_idle_notifier_v1_interface.name) == 0) {
logDbg("Got idle notifier");
ctx->idle_notifier = wl_registry_bind(registry, name, &ext_idle_notifier_v1_interface, version);
}
}

Expand Down Expand Up @@ -566,7 +569,9 @@ bool wlSetup(struct wlContext *ctx, int width, int height, char *backend)

/* initiailize idle inhibition */
if (configTryBool("idle-inhibit/enable", true)) {
if (wlIdleInitKde(ctx)) {
if (wlIdleInitExt(ctx)) {
logInfo("Using ext-idle-notify-v1 idle inhibition protocol");
} else if (wlIdleInitKde(ctx)) {
logInfo("Using KDE idle inhibition protocol");
} else if (wlIdleInitGnome(ctx)) {
logInfo("Using GNOME idle inhibition through gnome-session-inhibit");
Expand Down
100 changes: 100 additions & 0 deletions src/wl_idle_ext.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "wayland.h"


struct ext_state {
struct ext_idle_notification_v1_listener listener;
struct ext_idle_notification_v1 *notification;
xkb_keycode_t key;
int key_raw;
long idle_time;
};

static void on_idle_mouse(void *data, struct ext_idle_notification_v1 *notification)
{
struct wlIdle *idle = data;
logDbg("Got idle event, responding with zero mouse move");
wlMouseRelativeMotion(idle->wl_ctx, 0, 0);
}
static void on_idle_key(void *data, struct ext_idle_notification_v1 *notification)
{
struct wlIdle *idle = data;
struct ext_state *ext = idle->state;
//Second try at this -- press a key we do not care about
logDbg("Got idle event, responding with keypress");
if (ext->key_raw != -1) {
wlKeyRaw(idle->wl_ctx, ext->key_raw, true);
wlKeyRaw(idle->wl_ctx, ext->key_raw, false);
} else {
wlKey(idle->wl_ctx, ext->key, 0, true);
wlKey(idle->wl_ctx, ext->key, 0, false);
}
}
static void on_resumed(void *data, struct ext_idle_notification_v1 *notification)
{
logDbg("Got resume event");
}

static void inhibit_start(struct wlIdle *idle)
{
struct ext_state *ext = idle->state;

ext->notification = ext_idle_notifier_v1_get_idle_notification(idle->wl_ctx->idle_notifier, ext->idle_time * 1000, idle->wl_ctx->seat);
if (!ext->notification) {
logErr("Could not get idle notification");
return;
}
ext_idle_notification_v1_add_listener(ext->notification, &ext->listener, idle);
wlDisplayFlush(idle->wl_ctx);
}

static void inhibit_stop(struct wlIdle *idle)
{
struct ext_state *ext = idle->state;

if (!ext->notification) {
logDbg("Idle already not inhibited");
return;
}
ext_idle_notification_v1_destroy(ext->notification);
wlDisplayFlush(idle->wl_ctx);
ext->notification = NULL;
}

bool wlIdleInitExt(struct wlContext *ctx)
{
char *idle_method;
char *idle_keyname;

if (!ctx->idle_notifier) {
logWarn("ext-idle-notify-v1 idle inhibit selected, but no idle notifier support");
return false;
}
struct ext_state *ext = xcalloc(1, sizeof(*ext));
ext->listener.resumed = on_resumed;

ext->idle_time = configTryLong("idle-inhibit/interval", 30);
idle_method = configTryString("idle-inhibit/method", "mouse");

if (!strcmp(idle_method, "mouse")) {
ext->listener.idled = on_idle_mouse;
} else if (!strcmp(idle_method, "key")) {
ext->listener.idled = on_idle_key;
/* first try a raw keycode for idle, because in case
* of uinput xkb map might be rather useless */
ext->key_raw = configTryLong("idle-inhibit/keycode", -1);
idle_keyname = configTryString("idle-inhibit/keyname", "HYPR");
ext->key = xkb_keymap_key_by_name(ctx->input.xkb_map, idle_keyname);
free(idle_keyname);
} else {
logErr("Unknown idle inhibition method %s, initialization failed", idle_method);
free(idle_method);
free(ext);
return false;
}
free(idle_method);
ctx->idle.wl_ctx = ctx;
ctx->idle.state = ext;
ctx->idle.inhibit_start = inhibit_start;
ctx->idle.inhibit_stop = inhibit_stop;
return true;
}

0 comments on commit 5bd3307

Please sign in to comment.