[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