[Goodies-dev] [PATCH 2/4] Fix button refresh after suspend for Linux only

Olivier Brunel jjk at jjacky.com
Sun May 13 21:43:05 CEST 2018


Refreshing the button (to update date/time) is done via timeouts, but the
way they're implemented in GLib means they're not suspend aware, thus
the timeouts simply "resume"/keep going on resume, and as a result the
update/refreshing might come a little while after needed/resuming from
suspend.

This is fixed by using suspend-aware timeout sources, based on absolute
time on CLOCK_REALTIME. However, this is implemented via Linux-specific
interface (timerfd) and thus only works there.

If needed for other unices, an implementation using POSIX timer_create
& co might do the trick (but will force to play with signals).

Signed-off-by: Olivier Brunel <jjk at jjacky.com>
---
 configure.ac.in           |  12 ++++
 panel-plugin/Makefile.am  |   6 ++
 panel-plugin/datetime.h   |   4 ++
 panel-plugin/rt_timeout.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++
 panel-plugin/rt_timeout.h |  30 ++++++++++
 5 files changed, 195 insertions(+)
 create mode 100644 panel-plugin/rt_timeout.c
 create mode 100644 panel-plugin/rt_timeout.h

diff --git a/configure.ac.in b/configure.ac.in
index 679522e..599fed5 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -16,6 +16,18 @@ AM_INIT_AUTOMAKE([AC_PACKAGE_TARNAME()], [AC_PACKAGE_VERSION()])
 AM_CONFIG_HEADER([config.h])
 AM_MAINTAINER_MODE()
 
+dnl Get host type (host_os)
+AC_CANONICAL_HOST
+
+is_linux=no
+case "$host_os" in
+    linux*) is_linux=yes ;;
+esac
+AM_CONDITIONAL([LINUX], [test "$is_linux" = "yes"])
+if [test "$is_linux" = "yes"]; then
+    AC_DEFINE([LINUX], 1, [Linux])
+fi
+
 dnl Check for UNIX variants
 AC_AIX
 AC_ISC_POSIX
diff --git a/panel-plugin/Makefile.am b/panel-plugin/Makefile.am
index 97cd1cf..90d4740 100644
--- a/panel-plugin/Makefile.am
+++ b/panel-plugin/Makefile.am
@@ -9,6 +9,12 @@ libdatetime_la_SOURCES = 			\
 	datetime-dialog.h			\
 	datetime-dialog.c
 
+if LINUX
+libdatetime_la_SOURCES += 	\
+	rt_timeout.h	\
+	rt_timeout.c
+endif
+
 libdatetime_la_CFLAGS = 			\
 	-I$(top_srcdir)				\
 	-DLOCALEDIR=\"$(localedir)\"		\
diff --git a/panel-plugin/datetime.h b/panel-plugin/datetime.h
index f1f55e3..3fe434b 100644
--- a/panel-plugin/datetime.h
+++ b/panel-plugin/datetime.h
@@ -22,6 +22,10 @@
 #ifndef DATETIME_H
 #define DATETIME_H
 
+#ifdef LINUX
+#include "rt_timeout.h"
+#define g_timeout_add(ms,fn,data)   rt_timeout_add (ms, fn, data)
+#endif
 
 #include <libxfce4panel/xfce-panel-plugin.h>
 
diff --git a/panel-plugin/rt_timeout.c b/panel-plugin/rt_timeout.c
new file mode 100644
index 0000000..e161fe7
--- /dev/null
+++ b/panel-plugin/rt_timeout.c
@@ -0,0 +1,143 @@
+/*
+ *  From kalu: https://jjacky.com/kalu | https://github.com/jjk-jacky/kalu
+ *  Copyright (C) 2013-2018 Olivier Brunel <jjk at jjacky.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Library General Public License as published
+ *  by the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <sys/timerfd.h>
+#include <unistd.h>         /* close() */
+#include <time.h>
+#include "rt_timeout.h"
+
+struct _RtTimeoutSource
+{
+    GSource source;
+    GPollFD pollfd;
+    guint   interval;
+};
+
+static gboolean rt_timeout_prepare  (GSource *source, gint *timeout);
+static gboolean rt_timeout_check    (GSource *source);
+static gboolean rt_timeout_dispatch (GSource *source, GSourceFunc callback, gpointer data);
+static void     rt_timeout_finalize (GSource *source);
+
+static GSourceFuncs rt_timeout_funcs =
+{
+    .prepare    = rt_timeout_prepare,
+    .check      = rt_timeout_check,
+    .dispatch   = rt_timeout_dispatch,
+    .finalize   = rt_timeout_finalize
+};
+
+static gboolean
+rt_timeout_prepare (GSource *source __attribute__ ((unused)), gint *timeout)
+{
+    *timeout = -1;
+    return FALSE;
+}
+
+static gboolean
+rt_timeout_check (GSource *source)
+{
+    RtTimeoutSource *sce = (RtTimeoutSource *) source;
+    return (sce->pollfd.revents & G_IO_IN);
+}
+
+#define SECOND      1000000000
+static void set_value (struct timespec *tp, guint ms)
+{
+    time_t sec;
+    long nsec;
+
+    sec = ms / 1000;
+    nsec = (ms - 1000 * sec) * 1000000;
+
+    clock_gettime (CLOCK_REALTIME, tp);
+    tp->tv_sec += sec;
+    if (tp->tv_nsec + nsec > SECOND)
+    {
+        ++tp->tv_sec;
+        nsec -= SECOND;
+    }
+    tp->tv_nsec += nsec;
+}
+
+static gboolean
+rt_timeout_dispatch (GSource *source, GSourceFunc callback, gpointer data)
+{
+    gboolean again;
+
+    again = callback (data);
+    if (again)
+    {
+        RtTimeoutSource *sce = (RtTimeoutSource *) source;
+        struct itimerspec ts;
+
+        set_value (&ts.it_value, sce->interval);
+        ts.it_interval.tv_sec = 0;
+        ts.it_interval.tv_nsec = 0;
+        if (timerfd_settime (sce->pollfd.fd, TFD_TIMER_ABSTIME, &ts, NULL) == -1)
+            again = FALSE;
+    }
+    return again;
+}
+
+static void
+rt_timeout_finalize (GSource *source)
+{
+    RtTimeoutSource *sce = (RtTimeoutSource *) source;
+    close (sce->pollfd.fd);
+}
+
+guint
+rt_timeout_add (guint interval, GSourceFunc function, gpointer data)
+{
+    GSource          *source;
+    RtTimeoutSource  *sce;
+    guint             id;
+    struct itimerspec ts;
+
+    if (interval == 0)
+        return 0;
+
+    source = g_source_new (&rt_timeout_funcs, sizeof (RtTimeoutSource));
+    sce = (RtTimeoutSource *) source;
+
+    sce->pollfd.fd = timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK);
+    if (sce->pollfd.fd == -1)
+    {
+        g_source_unref (source);
+        return 0;
+    }
+    set_value (&ts.it_value, interval);
+    ts.it_interval.tv_sec = 0;
+    ts.it_interval.tv_nsec = 0;
+    if (timerfd_settime (sce->pollfd.fd, TFD_TIMER_ABSTIME, &ts, NULL) == -1)
+    {
+        g_source_unref (source);
+        return 0;
+    }
+
+    sce->pollfd.events = G_IO_IN | G_IO_ERR;
+    g_source_add_poll (source, &sce->pollfd);
+
+    sce->interval = interval;
+    g_source_set_callback (source, function, data, NULL);
+
+    id = g_source_attach (source, NULL);
+    g_source_unref (source);
+    return id;
+}
diff --git a/panel-plugin/rt_timeout.h b/panel-plugin/rt_timeout.h
new file mode 100644
index 0000000..62d12ed
--- /dev/null
+++ b/panel-plugin/rt_timeout.h
@@ -0,0 +1,30 @@
+/*
+ *  From kalu: https://jjacky.com/kalu | https://github.com/jjk-jacky/kalu
+ *  Copyright (C) 2013-2018 Olivier Brunel <jjk at jjacky.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Library General Public License as published
+ *  by the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _KALU_RT_TIMEOUT_H
+#define _KALU_RT_TIMEOUT_H
+
+/* glib */
+#include <glib-2.0/glib.h>
+
+typedef struct _RtTimeoutSource RtTimeoutSource;
+
+guint rt_timeout_add (guint interval, GSourceFunc function, gpointer data);
+
+#endif /* _KALU_RT_TIMEOUT_H */
-- 
2.15.1



More information about the Goodies-dev mailing list