312 lines
11 KiB
Diff
312 lines
11 KiB
Diff
From 5bd33075416dbb0bf22ffb7a0629faff685468de Mon Sep 17 00:00:00 2001
|
|
From: Ryan Farley <ryan.farley@gmx.com>
|
|
Date: Wed, 6 Mar 2024 04:38:01 -0600
|
|
Subject: [PATCH] idle: support ext-idle-notify-v1 protocol
|
|
|
|
wlroots no longer supports the old KDE one, so this is necessary. Keep
|
|
the old one around for now.
|
|
---
|
|
include/wayland.h | 5 +-
|
|
meson.build | 1 +
|
|
protocol/ext-idle-notify-v1.xml | 102 ++++++++++++++++++++++++++++++++
|
|
protocol/meson.build | 1 +
|
|
src/wayland.c | 7 ++-
|
|
src/wl_idle_ext.c | 100 +++++++++++++++++++++++++++++++
|
|
6 files changed, 214 insertions(+), 2 deletions(-)
|
|
create mode 100644 protocol/ext-idle-notify-v1.xml
|
|
create mode 100644 src/wl_idle_ext.c
|
|
|
|
diff --git a/include/wayland.h b/include/wayland.h
|
|
index 7f100f3..2e47d2f 100644
|
|
--- a/include/wayland.h
|
|
+++ b/include/wayland.h
|
|
@@ -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"
|
|
|
|
|
|
@@ -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);
|
|
|
|
@@ -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;
|
|
diff --git a/meson.build b/meson.build
|
|
index 9c2f8c2..5b7722b 100644
|
|
--- a/meson.build
|
|
+++ b/meson.build
|
|
@@ -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',
|
|
diff --git a/protocol/ext-idle-notify-v1.xml b/protocol/ext-idle-notify-v1.xml
|
|
new file mode 100644
|
|
index 0000000..6fe97d7
|
|
--- /dev/null
|
|
+++ b/protocol/ext-idle-notify-v1.xml
|
|
@@ -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>
|
|
diff --git a/protocol/meson.build b/protocol/meson.build
|
|
index b0d2242..1d554a3 100644
|
|
--- a/protocol/meson.build
|
|
+++ b/protocol/meson.build
|
|
@@ -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'],
|
|
diff --git a/src/wayland.c b/src/wayland.c
|
|
index 73f8f2f..7d91bcd 100644
|
|
--- a/src/wayland.c
|
|
+++ b/src/wayland.c
|
|
@@ -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);
|
|
}
|
|
}
|
|
|
|
@@ -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");
|
|
diff --git a/src/wl_idle_ext.c b/src/wl_idle_ext.c
|
|
new file mode 100644
|
|
index 0000000..68c5d24
|
|
--- /dev/null
|
|
+++ b/src/wl_idle_ext.c
|
|
@@ -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;
|
|
+}
|