waynergy/waynergy-0.0.16-upstream-support-ext-idle-notify-v1-protocol.patch

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;
+}