diff --git a/0001-Prefer-X11-to-Wayland-GDK-backend.patch b/0001-Prefer-X11-to-Wayland-GDK-backend.patch index f4fabc3..907ef64 100644 --- a/0001-Prefer-X11-to-Wayland-GDK-backend.patch +++ b/0001-Prefer-X11-to-Wayland-GDK-backend.patch @@ -1,28 +1,24 @@ -From d272dbc52a5d573a846ee7ba0f2fcd0de9b7708b Mon Sep 17 00:00:00 2001 +From a675908b8c2094a682208fa759a27b4b3dc059ee Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Thu, 26 Jul 2018 16:40:10 +0200 -Subject: [PATCH] Prefer X11 to Wayland GDK backend +Subject: [PATCH 1/2] Prefer X11 to Wayland GDK backend Gtk.StatusIcon is not implemented for Wayland. -Idle detection (as currently implemented using libXss) detects -only X11 clients' activity. -For now prefer running with the 'x11' GDK backend, where the status -icon works and user activity is detected at least in Gajim itself. +Prefer running with the 'x11' GDK backend, where the status icon works. --- - gajim/gajim.py | 5 +++++ - 1 file changed, 5 insertions(+) + gajim/gajim.py | 4 ++++ + 1 file changed, 4 insertions(+) diff --git a/gajim/gajim.py b/gajim/gajim.py -index c2e1f9ace5..1d0b2b68ae 100644 +index c2e1f9ace5..56923bc5fb 100644 --- a/gajim/gajim.py +++ b/gajim/gajim.py -@@ -43,6 +43,11 @@ import signal +@@ -43,6 +43,10 @@ import signal import locale from urllib.parse import unquote +# Prefer x11 to wayland for a working Gtk.StatusIcon -+# and at least partially working idle detection (libXss). +if 'GDK_BACKEND' not in os.environ: + os.environ['GDK_BACKEND']='x11' + diff --git a/0002-Support-for-idle-time-under-GNOME-without-X11.patch b/0002-Support-for-idle-time-under-GNOME-without-X11.patch new file mode 100644 index 0000000..35fda9c --- /dev/null +++ b/0002-Support-for-idle-time-under-GNOME-without-X11.patch @@ -0,0 +1,231 @@ +From fd2e847cafa9a2985b36f49919338ed7864b5456 Mon Sep 17 00:00:00 2001 +From: Sophie Herold +Date: Sun, 20 May 2018 16:07:08 +0200 +Subject: [PATCH 2/2] Support for idle time under GNOME without X11 + +* Removes use of most global variables +* Adds some some logging +* Removes unused close() method for Xss + +(cherry picked from commit 2e5d966f1d715f20f112dd9370f6ccd13fcaeca9) +--- + gajim/common/idle.py | 168 ++++++++++++++++++++++++++++------------- + gajim/common/sleepy.py | 3 +- + 2 files changed, 115 insertions(+), 56 deletions(-) + +diff --git a/gajim/common/idle.py b/gajim/common/idle.py +index 9e475c47dd..4a715294eb 100644 +--- a/gajim/common/idle.py ++++ b/gajim/common/idle.py +@@ -18,6 +18,58 @@ + + import ctypes + import ctypes.util ++import logging ++from gi.repository import Gio ++from gi.repository import GLib ++ ++log = logging.getLogger('gajim.c.idle') ++ ++idle_monitor = None ++ ++ ++class DBusGnomeIdleMonitor: ++ ++ def __init__(self): ++ self.last_idle_time = 0 ++ ++ log.debug('Connecting to D-Bus') ++ self.dbus_gnome_proxy = Gio.DBusProxy.new_for_bus_sync( ++ Gio.BusType.SESSION, ++ Gio.DBusProxyFlags.NONE, ++ None, ++ 'org.gnome.Mutter.IdleMonitor', ++ '/org/gnome/Mutter/IdleMonitor/Core', ++ 'org.gnome.Mutter.IdleMonitor', ++ None ++ ) ++ log.debug('D-Bus connected') ++ ++ # Only the following call will trigger exceptions if the D-Bus ++ # interface/method/... does not exist. Using the failing method ++ # for class init to allow other idle monitors to be used on failure. ++ self._get_idle_sec_fail() ++ log.debug('D-Bus call test successful') ++ ++ def _get_idle_sec_fail(self): ++ (idle_time,) = self.dbus_gnome_proxy.call_sync( ++ 'GetIdletime', ++ None, ++ Gio.DBusCallFlags.NO_AUTO_START, ++ -1, ++ None ++ ) ++ return int(idle_time / 1000) ++ ++ def get_idle_sec(self): ++ try: ++ self.last_idle_time = self._get_idle_sec_fail() ++ except GLib.Error as e: ++ log.warning( ++ 'org.gnome.Mutter.IdleMonitor.GetIdletime() failed: %s', ++ repr(e)) ++ ++ return self.last_idle_time ++ + + class XScreenSaverInfo(ctypes.Structure): + _fields_ = [ +@@ -28,72 +80,80 @@ class XScreenSaverInfo(ctypes.Structure): + ('idle', ctypes.c_ulong), + ('eventMask', ctypes.c_ulong) + ] +-XScreenSaverInfo_p = ctypes.POINTER(XScreenSaverInfo) + +-display_p = ctypes.c_void_p +-xid = ctypes.c_ulong +-c_int_p = ctypes.POINTER(ctypes.c_int) + +-try: +- libX11path = ctypes.util.find_library('X11') +- if libX11path == None: +- raise OSError('libX11 could not be found.') +- libX11 = ctypes.cdll.LoadLibrary(libX11path) +- libX11.XOpenDisplay.restype = display_p +- libX11.XOpenDisplay.argtypes = ctypes.c_char_p, +- libX11.XDefaultRootWindow.restype = xid +- libX11.XDefaultRootWindow.argtypes = display_p, +- +- libXsspath = ctypes.util.find_library('Xss') +- if libXsspath == None: +- raise OSError('libXss could not be found.') +- libXss = ctypes.cdll.LoadLibrary(libXsspath) +- libXss.XScreenSaverQueryExtension.argtypes = display_p, c_int_p, c_int_p +- libXss.XScreenSaverAllocInfo.restype = XScreenSaverInfo_p +- libXss.XScreenSaverQueryInfo.argtypes = (display_p, xid, XScreenSaverInfo_p) +- +- dpy_p = libX11.XOpenDisplay(None) +- if dpy_p == None: +- raise OSError('Could not open X Display.') +- +- _event_basep = ctypes.c_int() +- _error_basep = ctypes.c_int() +- if libXss.XScreenSaverQueryExtension(dpy_p, ctypes.byref(_event_basep), +- ctypes.byref(_error_basep)) == 0: +- raise OSError('XScreenSaver Extension not available on display.') +- +- xss_info_p = libXss.XScreenSaverAllocInfo() +- if xss_info_p == None: +- raise OSError('XScreenSaverAllocInfo: Out of Memory.') +- +- rootwindow = libX11.XDefaultRootWindow(dpy_p) +- xss_available = True +-except OSError: +- # Logging? +- xss_available = False ++class XssIdleMonitor: ++ def __init__(self): ++ XScreenSaverInfo_p = ctypes.POINTER(XScreenSaverInfo) ++ ++ display_p = ctypes.c_void_p ++ xid = ctypes.c_ulong ++ c_int_p = ctypes.POINTER(ctypes.c_int) ++ ++ libX11path = ctypes.util.find_library('X11') ++ if libX11path == None: ++ raise OSError('libX11 could not be found.') ++ libX11 = ctypes.cdll.LoadLibrary(libX11path) ++ libX11.XOpenDisplay.restype = display_p ++ libX11.XOpenDisplay.argtypes = ctypes.c_char_p, ++ libX11.XDefaultRootWindow.restype = xid ++ libX11.XDefaultRootWindow.argtypes = display_p, ++ ++ libXsspath = ctypes.util.find_library('Xss') ++ if libXsspath == None: ++ raise OSError('libXss could not be found.') ++ self.libXss = ctypes.cdll.LoadLibrary(libXsspath) ++ self.libXss.XScreenSaverQueryExtension.argtypes = display_p, c_int_p, c_int_p ++ self.libXss.XScreenSaverAllocInfo.restype = XScreenSaverInfo_p ++ self.libXss.XScreenSaverQueryInfo.argtypes = (display_p, xid, XScreenSaverInfo_p) ++ ++ self.dpy_p = libX11.XOpenDisplay(None) ++ if self.dpy_p == None: ++ raise OSError('Could not open X Display.') ++ ++ _event_basep = ctypes.c_int() ++ _error_basep = ctypes.c_int() ++ if self.libXss.XScreenSaverQueryExtension(self.dpy_p, ctypes.byref(_event_basep), ++ ctypes.byref(_error_basep)) == 0: ++ raise OSError('XScreenSaver Extension not available on display.') ++ ++ self.xss_info_p = self.libXss.XScreenSaverAllocInfo() ++ if self.xss_info_p == None: ++ raise OSError('XScreenSaverAllocInfo: Out of Memory.') ++ ++ self.rootwindow = libX11.XDefaultRootWindow(self.dpy_p) ++ ++ def get_idle_sec(self): ++ if self.libXss.XScreenSaverQueryInfo( ++ self.dpy_p, ++ self.rootwindow, ++ self.xss_info_p) == 0: ++ return 0 ++ else: ++ return int(self.xss_info_p.contents.idle / 1000) ++ + + def getIdleSec(): +- global xss_available + """ + Return the idle time in seconds + """ +- if not xss_available: +- return 0 +- if libXss.XScreenSaverQueryInfo(dpy_p, rootwindow, xss_info_p) == 0: ++ if idle_monitor is None: + return 0 + else: +- return int(xss_info_p.contents.idle) / 1000 ++ return idle_monitor.get_idle_sec() + +-def close(): +- global xss_available +- if xss_available: +- libX11.XFree(xss_info_p) +- libX11.XCloseDisplay(dpy_p) +- xss_available = False ++try: ++ idle_monitor = DBusGnomeIdleMonitor() ++except GLib.Error as e: ++ log.info("Idle time via D-Bus not available: %s", repr(e)) ++ ++ try: ++ idle_monitor = XssIdleMonitor() ++ except OSError as e: ++ log.info("Idle time via XScreenSaverInfo not available: %s", repr(e)) ++ raise Exception('No supported idle monitor found') + + if __name__ == '__main__': + import time + time.sleep(2.1) + print(getIdleSec()) +- close() +- print(getIdleSec()) +diff --git a/gajim/common/sleepy.py b/gajim/common/sleepy.py +index ca3395e520..721766d910 100644 +--- a/gajim/common/sleepy.py ++++ b/gajim/common/sleepy.py +@@ -53,9 +53,8 @@ try: + SystemParametersInfo = ctypes.windll.user32.SystemParametersInfoW + else: # unix + from gajim.common import idle +- idle.xss_available + except Exception: +- log.debug('Unable to load idle module') ++ log.warning('Unable to load idle module') + SUPPORTED = False + + class SleepyWindows: +-- +2.17.1 + diff --git a/gajim.spec b/gajim.spec index 3d67471..fca9df7 100644 --- a/gajim.spec +++ b/gajim.spec @@ -4,11 +4,12 @@ Summary: Jabber client written in PyGTK Name: gajim %global majorver 1.0 Version: 1.0.3 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv3 URL: https://gajim.org/ Source0: https://gajim.org/downloads/%{majorver}/%{name}-%{version}.tar.bz2 Patch1: 0001-Prefer-X11-to-Wayland-GDK-backend.patch +Patch2: 0002-Support-for-idle-time-under-GNOME-without-X11.patch BuildArch: noarch ## Hard requirements @@ -104,6 +105,9 @@ appstream-util validate-relax --nonet %{buildroot}%{_datadir}/metainfo/%{appid}. %{python3_sitelib}/%{name}-%{version}*.egg-info %changelog +* Thu Jul 26 2018 Michal Schmidt - 1.0.3-3 +- Apply upstream patch for getting idle time from Mutter (no X11 needed). + * Thu Jul 26 2018 Michal Schmidt - 1.0.3-2 - Prefer x11 backend for working status icon and idle detection.