[gnome-flashback] screensaver: add GfFade
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] screensaver: add GfFade
- Date: Tue, 11 Feb 2020 13:04:37 +0000 (UTC)
commit 2d3c419d4f304ed021f92cab83f0f828a1ec09a4
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Tue Feb 11 14:27:24 2020 +0200
screensaver: add GfFade
.gitlab-ci.yml | 1 +
configure.ac | 2 +
gnome-flashback/libscreensaver/Makefile.am | 2 +
gnome-flashback/libscreensaver/gf-fade.c | 510 +++++++++++++++++++++++++++++
gnome-flashback/libscreensaver/gf-fade.h | 50 +++
5 files changed, 565 insertions(+)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4e97944..f503552 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -44,6 +44,7 @@ build-ubuntu:
libxi-dev
libxkbfile-dev
libxrandr-dev
+ libxxf86vm-dev
xkb-data
script:
- ./autogen.sh
diff --git a/configure.ac b/configure.ac
index 7bb5ad2..a08e843 100644
--- a/configure.ac
+++ b/configure.ac
@@ -99,6 +99,7 @@ POLKIT_GOBJECT_REQUIRED=0.97
IBUS_REQUIRED=1.5.2
UPOWER_GLIB_REQUIRED=0.99.0
XRANDR_REQUIRED=1.5.0
+XXF86VM_REQUIRED=1.1.4
PKG_CHECK_MODULES([DBUS], [
gio-2.0 >= $GLIB_REQUIRED
@@ -227,6 +228,7 @@ PKG_CHECK_MODULES([SCREENSAVER], [
gnome-desktop-3.0 >= $LIBGNOME_DESKTOP_REQUIRED
gtk+-3.0 >= $GTK_REQUIRED
libsystemd
+ xxf86vm >= $XXF86VM_REQUIRED
])
PKG_CHECK_MODULES([SCREENSHOT], [
diff --git a/gnome-flashback/libscreensaver/Makefile.am b/gnome-flashback/libscreensaver/Makefile.am
index e1e507f..e713143 100644
--- a/gnome-flashback/libscreensaver/Makefile.am
+++ b/gnome-flashback/libscreensaver/Makefile.am
@@ -24,6 +24,8 @@ libscreensaver_la_CFLAGS = \
libscreensaver_la_SOURCES = \
gf-auth.c \
gf-auth.h \
+ gf-fade.c \
+ gf-fade.h \
gf-grab.c \
gf-grab.h \
gf-info-bar.c \
diff --git a/gnome-flashback/libscreensaver/gf-fade.c b/gnome-flashback/libscreensaver/gf-fade.c
new file mode 100644
index 0000000..aa600c9
--- /dev/null
+++ b/gnome-flashback/libscreensaver/gf-fade.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2004-2009 William Jon McCann
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2020 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * William Jon McCann <mccann jhu edu>
+ */
+
+#include "config.h"
+#include "gf-fade.h"
+
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/xf86vmode.h>
+
+#define XF86_MIN_GAMMA 0.1f
+
+/* VidModeExtension version 2.0 or better is needed to do gamma.
+ * 2.0 added gamma values; 2.1 added gamma ramps.
+ */
+#define XF86_VIDMODE_GAMMA_MIN_MAJOR 2
+#define XF86_VIDMODE_GAMMA_MIN_MINOR 0
+#define XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR 2
+#define XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR 1
+
+typedef enum
+{
+ GF_FADE_TYPE_NONE,
+ GF_FADE_TYPE_GAMMA_NUMBER,
+ GF_FADE_TYPE_GAMMA_RAMP
+} GfFadeType;
+
+typedef struct
+{
+ int size;
+ unsigned short *r;
+ unsigned short *g;
+ unsigned short *b;
+} GfGammaInfo;
+
+struct _GfFade
+{
+ GObject parent;
+
+ GfFadeType fade_type;
+
+ gboolean (* fade_setup) (GfFade *self);
+
+ gboolean (* fade_set_alpha_gamma) (GfFade *self,
+ double alpha);
+
+ void (* fade_finish) (GfFade *self);
+
+ int num_ramps;
+
+ GfGammaInfo *info;
+
+ XF86VidModeGamma vmg;
+
+ GList *tasks;
+
+ double alpha_per_iter;
+ double current_alpha;
+
+ guint timeout_id;
+};
+
+G_DEFINE_TYPE (GfFade, gf_fade, G_TYPE_OBJECT)
+
+static void
+screen_fade_finish (GfFade *self)
+{
+ int i;
+
+ if (self->info == NULL)
+ return;
+
+ for (i = 0; i < self->num_ramps; i++)
+ {
+ g_clear_pointer (&self->info[i].r, g_free);
+ g_clear_pointer (&self->info[i].g, g_free);
+ g_clear_pointer (&self->info[i].b, g_free);
+ }
+
+ g_clear_pointer (&self->info, g_free);
+}
+
+static gboolean
+setup_gamma_ramp (GfFade *self)
+{
+ GdkDisplay *display;
+ Display *xdisplay;
+ gboolean res;
+
+ display = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ res = XF86VidModeGetGammaRampSize (xdisplay,
+ XDefaultScreen (xdisplay),
+ &self->info->size);
+
+ if (!res || self->info->size <= 0)
+ return FALSE;
+
+ self->info->r = g_new0 (unsigned short, self->info->size);
+ self->info->g = g_new0 (unsigned short, self->info->size);
+ self->info->b = g_new0 (unsigned short, self->info->size);
+
+ if (!(self->info->r && self->info->g && self->info->b))
+ return FALSE;
+
+ return XF86VidModeGetGammaRamp (xdisplay,
+ XDefaultScreen (xdisplay),
+ self->info->size,
+ self->info->r,
+ self->info->g,
+ self->info->b);
+}
+
+static gboolean
+gamma_fade_setup (GfFade *self)
+{
+ if (self->info != NULL)
+ return TRUE;
+
+ self->num_ramps = 1;
+ self->info = g_new0 (GfGammaInfo, 1);
+
+ if (self->fade_type == GF_FADE_TYPE_GAMMA_RAMP)
+ {
+ /* have ramps */
+
+ if (setup_gamma_ramp (self))
+ {
+ g_debug ("Initialized gamma ramp fade");
+ return TRUE;
+ }
+
+ self->fade_type = GF_FADE_TYPE_GAMMA_NUMBER;
+ }
+
+ if (self->fade_type == GF_FADE_TYPE_GAMMA_NUMBER)
+ {
+ GdkDisplay *display;
+ Display *xdisplay;
+
+ /* only have gamma parameter, not ramps. */
+
+ display = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ if (XF86VidModeGetGamma (xdisplay, XDefaultScreen (xdisplay), &self->vmg))
+ {
+ g_debug ("Initialized gamma fade: %f %f %f",
+ (double) self->vmg.red,
+ (double) self->vmg.green,
+ (double) self->vmg.blue);
+
+ return TRUE;
+ }
+ }
+
+ self->fade_type = GF_FADE_TYPE_NONE;
+ return FALSE;
+}
+
+static void
+xf86_whack_gamma (GfFade *self,
+ float ratio)
+{
+ GdkDisplay *display;
+ Display *xdisplay;
+
+ if (self->info == NULL)
+ return;
+
+ if (ratio < 0.0f)
+ ratio = 0.0;
+ else if (ratio > 1.0f)
+ ratio = 1.0;
+
+ display = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ if (self->info->size == 0)
+ {
+ XF86VidModeGamma g2;
+
+ /* we only have a gamma number, not a ramp. */
+
+ g2.red = self->vmg.red * ratio;
+ g2.green = self->vmg.green * ratio;
+ g2.blue = self->vmg.blue * ratio;
+
+ if (g2.red < XF86_MIN_GAMMA)
+ g2.red = XF86_MIN_GAMMA;
+
+ if (g2.green < XF86_MIN_GAMMA)
+ g2.green = XF86_MIN_GAMMA;
+
+ if (g2.blue < XF86_MIN_GAMMA)
+ g2.blue = XF86_MIN_GAMMA;
+
+ XF86VidModeSetGamma (xdisplay, XDefaultScreen (xdisplay), &g2);
+ }
+ else
+ {
+ unsigned short *r;
+ unsigned short *g;
+ unsigned short *b;
+ int i;
+
+ r = g_new0 (unsigned short, self->info->size);
+ g = g_new0 (unsigned short, self->info->size);
+ b = g_new0 (unsigned short, self->info->size);
+
+ for (i = 0; i < self->info->size; i++)
+ {
+ r[i] = self->info->r[i] * ratio;
+ g[i] = self->info->g[i] * ratio;
+ b[i] = self->info->b[i] * ratio;
+ }
+
+ XF86VidModeSetGammaRamp (xdisplay,
+ XDefaultScreen (xdisplay),
+ self->info->size,
+ r, g, b);
+
+ g_free (r);
+ g_free (g);
+ g_free (b);
+ }
+
+ gdk_display_flush (display);
+}
+
+static gboolean
+gamma_fade_set_alpha_gamma (GfFade *self,
+ double alpha)
+{
+ xf86_whack_gamma (self, alpha);
+ return TRUE;
+}
+
+static void
+check_gamma_extension (GfFade *self)
+{
+ GdkDisplay *display;
+ Display *xdisplay;
+ int event;
+ int error;
+ gboolean res;
+ int major;
+ int minor;
+
+ display = gdk_display_get_default ();
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ if (!XF86VidModeQueryExtension (xdisplay, &event, &error))
+ return;
+
+ gdk_x11_display_error_trap_push (display);
+
+ res = XF86VidModeQueryVersion (xdisplay, &major, &minor);
+
+ if (gdk_x11_display_error_trap_pop (display) != 0 || !res)
+ return;
+
+ g_debug ("Gamma extension version: major - %d, minor - %d", major, minor);
+
+ if (major < XF86_VIDMODE_GAMMA_MIN_MAJOR ||
+ (major == XF86_VIDMODE_GAMMA_MIN_MAJOR &&
+ minor < XF86_VIDMODE_GAMMA_MIN_MINOR))
+ return;
+
+ self->fade_setup = gamma_fade_setup;
+ self->fade_finish = screen_fade_finish;
+ self->fade_set_alpha_gamma = gamma_fade_set_alpha_gamma;
+
+ if (major < XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR ||
+ (major == XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR &&
+ minor < XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR))
+ {
+ self->fade_type = GF_FADE_TYPE_GAMMA_NUMBER;
+ return;
+ }
+
+ self->fade_type = GF_FADE_TYPE_GAMMA_RAMP;
+}
+
+static void
+check_extensions (GfFade *self)
+{
+ if (self->fade_type == GF_FADE_TYPE_NONE)
+ check_gamma_extension (self);
+
+ g_debug ("Fade type: %d", self->fade_type);
+}
+
+static gboolean
+set_alpha (GfFade *self,
+ gdouble alpha)
+{
+ switch (self->fade_type)
+ {
+ case GF_FADE_TYPE_GAMMA_RAMP:
+ case GF_FADE_TYPE_GAMMA_NUMBER:
+ if (self->fade_set_alpha_gamma != NULL)
+ self->fade_set_alpha_gamma (self, alpha);
+ return TRUE;
+
+ case GF_FADE_TYPE_NONE:
+ break;
+
+ default:
+ g_warning ("Unknown fade type");
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+fade_stop (GfFade *self)
+{
+ if (self->timeout_id != 0)
+ {
+ g_source_remove (self->timeout_id);
+ self->timeout_id = 0;
+ }
+}
+
+static gboolean
+fade_out_iter (GfFade *self)
+{
+ if (self->current_alpha < 0.01)
+ return FALSE;
+
+ self->current_alpha -= self->alpha_per_iter;
+
+ return set_alpha (self, self->current_alpha);
+}
+
+static void
+gf_fade_complete (GfFade *self)
+{
+ GList *l;
+
+ if (self->tasks == NULL)
+ return;
+
+ fade_stop (self);
+
+ for (l = self->tasks; l != NULL; l = l->next)
+ g_task_return_boolean (G_TASK (l->data), TRUE);
+
+ g_list_free_full (self->tasks, g_object_unref);
+ self->tasks = NULL;
+}
+
+static gboolean
+fade_out_cb (gpointer user_data)
+{
+ GfFade *self;
+
+ self = GF_FADE (user_data);
+
+ if (!fade_out_iter (self))
+ {
+ gf_fade_complete (self);
+ self->timeout_id = 0;
+
+ return G_SOURCE_REMOVE;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+fade_start (GfFade *self,
+ guint timeout)
+{
+ fade_stop (self);
+
+ if (self->fade_type != GF_FADE_TYPE_NONE)
+ {
+ guint steps_per_sec;
+ guint num_steps;
+
+ if (!self->fade_setup (self))
+ {
+ gf_fade_complete (self);
+ return;
+ }
+
+ steps_per_sec = 60;
+ num_steps = (timeout / 1000.0) * steps_per_sec;
+
+ self->alpha_per_iter = 1.0 / (double) num_steps;
+
+ self->timeout_id = g_timeout_add (1000 / steps_per_sec, fade_out_cb, self);
+ g_source_set_name_by_id (self->timeout_id, "[gnome-flashback] fade_out_cb");
+ }
+ else
+ {
+ gf_fade_complete (self);
+ }
+}
+
+static void
+gf_fade_dispose (GObject *object)
+{
+ GfFade *self;
+
+ self = GF_FADE (object);
+
+ fade_stop (self);
+
+ if (self->fade_finish != NULL)
+ self->fade_finish (self);
+
+ if (self->tasks != NULL)
+ {
+ g_list_free_full (self->tasks, g_object_unref);
+ self->tasks = NULL;
+ }
+
+ G_OBJECT_CLASS (gf_fade_parent_class)->dispose (object);
+}
+
+static void
+gf_fade_class_init (GfFadeClass *self_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (self_class);
+
+ object_class->dispose = gf_fade_dispose;
+}
+
+static void
+gf_fade_init (GfFade *self)
+{
+ self->fade_type = GF_FADE_TYPE_NONE;
+ self->current_alpha = 1.0;
+
+ check_extensions (self);
+}
+
+GfFade *
+gf_fade_new (void)
+{
+ return g_object_new (GF_TYPE_FADE, NULL);
+}
+
+void
+gf_fade_async (GfFade *self,
+ guint timeout,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ fade_stop (self);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ self->tasks = g_list_prepend (self->tasks, task);
+
+ fade_start (self, timeout);
+}
+
+gboolean
+gf_fade_finish (GfFade *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+void
+gf_fade_reset (GfFade *self)
+{
+ g_debug ("Resetting fade");
+
+ fade_stop (self);
+
+ self->current_alpha = 1.0;
+ set_alpha (self, self->current_alpha);
+
+ if (self->fade_finish != NULL)
+ self->fade_finish (self);
+}
diff --git a/gnome-flashback/libscreensaver/gf-fade.h b/gnome-flashback/libscreensaver/gf-fade.h
new file mode 100644
index 0000000..de7c562
--- /dev/null
+++ b/gnome-flashback/libscreensaver/gf-fade.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2004-2005 William Jon McCann
+ * Copyright (C) 2020 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * William Jon McCann <mccann jhu edu>
+ */
+
+#ifndef GF_FADE_H
+#define GF_FADE_H
+
+#include <gio/gio.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GF_TYPE_FADE (gf_fade_get_type ())
+G_DECLARE_FINAL_TYPE (GfFade, gf_fade, GF, FADE, GObject)
+
+GfFade *gf_fade_new (void);
+
+void gf_fade_async (GfFade *self,
+ guint timeout,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gf_fade_finish (GfFade *self,
+ GAsyncResult *result,
+ GError **error);
+
+void gf_fade_reset (GfFade *self);
+
+G_END_DECLS
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]