From 3c620f6fd15e028ec0883fe2637c9721f46f6ec1 Mon Sep 17 00:00:00 2001 From: miruka Date: Sat, 11 Jul 2020 00:51:53 -0400 Subject: [PATCH] Add auto-away feature for Linux X11 --- TODO.md | 5 +++- mirage.pro | 4 ++++ src/backend/matrix_client.py | 15 ++++++++---- src/backend/models/items.py | 1 + src/backend/nio_callbacks.py | 13 ++++++----- src/backend/user_files.py | 1 + src/clipboard.h | 3 +-- src/gui/IdleManager.qml | 45 ++++++++++++++++++++++++++++++++++++ src/gui/UI.qml | 5 ++++ src/utils.h | 30 ++++++++++++++++++++++-- 10 files changed, 107 insertions(+), 15 deletions(-) create mode 100644 src/gui/IdleManager.qml diff --git a/TODO.md b/TODO.md index e09678fb..2cc863d1 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,9 @@ # TODO -- account can't see another's status message once it goes offline +- mark accounts as offline when closing mirage +- document new x11 dependnecy (auto-idle) +- auto-idle for Windows and OSX +- open context menus centered on touch screens - retrieve last seen time for offline members on hover/in profile - auto-away after a configurable idle time - status based on process detection diff --git a/mirage.pro b/mirage.pro index e475b289..4bebd871 100644 --- a/mirage.pro +++ b/mirage.pro @@ -16,6 +16,10 @@ HEADERS += src/utils.h src/clipboard.h submodules/hsluv-c/src/hsluv.h SOURCES += src/main.cpp submodules/hsluv-c/src/hsluv.c TARGET = mirage +unix:!macx { + LIBS += -lX11 -lXss +} + # Custom CONFIG options diff --git a/src/backend/matrix_client.py b/src/backend/matrix_client.py index 0189dc25..142c1695 100644 --- a/src/backend/matrix_client.py +++ b/src/backend/matrix_client.py @@ -1290,7 +1290,10 @@ class MatrixClient(nio.AsyncClient): async def set_presence( - self, presence: str, status_msg: Optional[str] = None, + self, + presence: str, + status_msg: Optional[str] = None, + save: bool = True, ) -> None: """Set presence state for this account.""" @@ -1326,9 +1329,13 @@ class MatrixClient(nio.AsyncClient): if not account.presence_support: account.presence = Presence.State(presence) - await self.backend.saved_accounts.update( - self.user_id, presence=presence, - ) + if save: + account.save_presence = True + await self.backend.saved_accounts.update( + self.user_id, presence=presence, + ) + else: + account.save_presence = False await super().set_presence( "offline" if presence == "invisible" else presence, diff --git a/src/backend/models/items.py b/src/backend/models/items.py index ffbb4032..87287029 100644 --- a/src/backend/models/items.py +++ b/src/backend/models/items.py @@ -143,6 +143,7 @@ class Account(ModelItem): # For some reason, Account cannot inherit Presence, because QML keeps # complaining type error on unknown file presence_support: bool = False + save_presence: bool = True presence: Presence.State = Presence.State.offline currently_active: bool = False last_active_at: datetime = ZERO_DATE diff --git a/src/backend/nio_callbacks.py b/src/backend/nio_callbacks.py index e104d641..d96d71d8 100644 --- a/src/backend/nio_callbacks.py +++ b/src/backend/nio_callbacks.py @@ -632,12 +632,13 @@ class NioCallbacks: account.presence_support = True # Save the presence for the next resume - await self.client.backend.saved_accounts.update( - user_id = ev.user_id, - presence = presence.presence.value if ( - account.presence != Presence.State.echo_invisible - ) else "invisible", - ) + if account.save_presence: + await self.client.backend.saved_accounts.update( + user_id = ev.user_id, + presence = presence.presence.value if ( + account.presence != Presence.State.echo_invisible + ) else "invisible", + ) presence.update_account() diff --git a/src/backend/user_files.py b/src/backend/user_files.py index 65f405b2..6a8a10e3 100644 --- a/src/backend/user_files.py +++ b/src/backend/user_files.py @@ -248,6 +248,7 @@ class UISettings(JSONDataFile): "alertOnMentionForMsec": -1, "alertOnMessageForMsec": 0, "alwaysCenterRoomHeader": False, + "beUnavailableAfterSecondsIdle": 60 * 10, "compactMode": False, "clearRoomFilterOnEnter": True, "clearRoomFilterOnEscape": True, diff --git a/src/clipboard.h b/src/clipboard.h index c608e42d..372974be 100644 --- a/src/clipboard.h +++ b/src/clipboard.h @@ -11,8 +11,7 @@ #include -class Clipboard : public QObject -{ +class Clipboard : public QObject { Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QString selection READ selection WRITE setSelection diff --git a/src/gui/IdleManager.qml b/src/gui/IdleManager.qml new file mode 100644 index 00000000..3ca55c92 --- /dev/null +++ b/src/gui/IdleManager.qml @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +import QtQuick 2.12 +import CppUtils 0.1 +import "." + +Timer { + readonly property ListModel accounts: ModelStore.get("accounts") + readonly property var accountsSet: new Set() + + + function setPresence(userId, presence) { + py.callClientCoro(userId, "set_presence", [presence, undefined, false]) + } + + + interval: 1000 + running: window.settings.beUnavailableAfterSecondsIdle > 0 + repeat: true + + onTriggered: { + let changes = false + + const beUnavailable = + CppUtils.idleMilliseconds() / 1000 >= + window.settings.beUnavailableAfterSecondsIdle + + for (let i = 0; i < accounts.count; i++) { + const account = accounts.get(i) + + if (beUnavailable && account.presence === "online") { + setPresence(account.id, "unavailable") + accountsSet.add(account.id) + changes = true + + } else if (! beUnavailable && accountsSet.has(account.id)) { + setPresence(account.id, "online") + accountsSet.delete(account.id) + changes = true + } + } + + if (changes) accountsSetChanged() + } +} diff --git a/src/gui/UI.qml b/src/gui/UI.qml index 9cde40fd..fe4c9ec7 100644 --- a/src/gui/UI.qml +++ b/src/gui/UI.qml @@ -33,6 +33,7 @@ Item { readonly property alias pageLoader: pageLoader readonly property alias pressAnimation: pressAnimation readonly property alias fontMetrics: fontMetrics + readonly property alias idleManager: idleManager function reloadSettings() { @@ -96,6 +97,10 @@ Item { visible: false } + IdleManager { + id: idleManager + } + LinearGradient { id: mainUIGradient visible: ! image.visible diff --git a/src/utils.h b/src/utils.h index f3fbcf29..004bd52b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -11,12 +11,15 @@ #include #include +#ifdef Q_OS_UNIX +#include +#endif + #include "../submodules/hsluv-c/src/hsluv.h" class Utils : public QObject { - -Q_OBJECT + Q_OBJECT public: Utils() {}; @@ -44,6 +47,29 @@ public slots: ); } + int idleMilliseconds() const { + #ifdef Q_OS_DARWIN + return -1; + + #elif defined(Q_OS_UNIX) + Display *display = XOpenDisplay(NULL); + if (! display) return -1; + + XScreenSaverInfo *info = XScreenSaverAllocInfo(); + XScreenSaverQueryInfo(display, DefaultRootWindow(display), info); + const int idle = info->idle; + + XCloseDisplay(display); + return idle; + + #elif defined(Q_OS_WINDOWS) + return -1; + + #else + return -1; + #endif + } + private: QLocale appLocale; };