[gnome-flashback] desktop: handle background drawing



commit 7417f4762aa66d032d645310e1959ef4a6da3b2e
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Tue Oct 29 15:28:04 2019 +0200

    desktop: handle background drawing

 gnome-flashback/libdesktop/gf-background.c | 284 ++++++++++++++++++++++++++++-
 1 file changed, 280 insertions(+), 4 deletions(-)
---
diff --git a/gnome-flashback/libdesktop/gf-background.c b/gnome-flashback/libdesktop/gf-background.c
index 334bba1..5e88c02 100644
--- a/gnome-flashback/libdesktop/gf-background.c
+++ b/gnome-flashback/libdesktop/gf-background.c
@@ -18,14 +18,38 @@
 #include "config.h"
 #include "gf-background.h"
 
+#include <libgnome-desktop/gnome-bg.h>
+
+#include "gf-desktop-window.h"
+
+typedef struct
+{
+  cairo_surface_t *start;
+  cairo_surface_t *end;
+
+  double           start_time;
+  double           total_duration;
+  gboolean         is_first_frame;
+  double           percent_done;
+
+  guint            timeout_id;
+} FadeData;
+
 struct _GfBackground
 {
-  GObject    parent;
+  GObject          parent;
+
+  GtkWidget       *window;
+
+  GSettings       *settings1;
+  GSettings       *settings2;
 
-  GtkWidget *window;
+  GnomeBG         *bg;
 
-  GSettings *settings1;
-  GSettings *settings2;
+  guint            change_id;
+
+  FadeData        *fade_data;
+  cairo_surface_t *surface;
 };
 
 enum
@@ -50,6 +74,213 @@ static guint background_signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (GfBackground, gf_background, G_TYPE_OBJECT)
 
+static void
+free_fade_data (FadeData *data)
+{
+  if (data->timeout_id != 0)
+    {
+      g_source_remove (data->timeout_id);
+      data->timeout_id = 0;
+    }
+
+  g_clear_pointer (&data->start, cairo_surface_destroy);
+  g_clear_pointer (&data->end, cairo_surface_destroy);
+  g_free (data);
+}
+
+static gboolean
+fade_cb (gpointer user_data)
+{
+  GfBackground *self;
+  FadeData *fade;
+  double current_time;
+  double percent_done;
+  GdkScreen *screen;
+
+  self = GF_BACKGROUND (user_data);
+  fade = self->fade_data;
+
+  current_time = g_get_real_time () / (double) G_USEC_PER_SEC;
+  percent_done = (current_time - fade->start_time) / fade->total_duration;
+  percent_done = CLAMP (percent_done, 0.0, 1.0);
+
+  if (fade->is_first_frame && percent_done > 0.33)
+    {
+      fade->total_duration *= 1.5;
+      fade->is_first_frame = FALSE;
+
+      return fade_cb (self);
+    }
+
+  gtk_widget_queue_draw (self->window);
+
+  fade->is_first_frame = FALSE;
+  fade->percent_done = percent_done;
+
+  if (percent_done < 0.99)
+    return G_SOURCE_CONTINUE;
+
+  self->fade_data->timeout_id = 0;
+
+  g_clear_pointer (&self->surface, cairo_surface_destroy);
+  self->surface = cairo_surface_reference (fade->end);
+
+  g_clear_pointer (&self->fade_data, free_fade_data);
+
+  screen = gtk_widget_get_screen (self->window);
+  gnome_bg_set_surface_as_root (screen, self->surface);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+change (GfBackground *self,
+        gboolean      fade)
+{
+  GdkScreen *screen;
+  GdkWindow *root;
+  int width;
+  int height;
+
+  screen = gtk_widget_get_screen (self->window);
+  root = gdk_screen_get_root_window (screen);
+
+  width = gf_desktop_window_get_width (GF_DESKTOP_WINDOW (self->window));
+  height = gf_desktop_window_get_height (GF_DESKTOP_WINDOW (self->window));
+
+  if (fade)
+    {
+      FadeData *data;
+
+      g_assert (self->fade_data == NULL);
+      self->fade_data = data = g_new0 (FadeData, 1);
+
+      if (self->surface != NULL)
+        data->start = cairo_surface_reference (self->surface);
+      else
+        data->start = gnome_bg_get_surface_from_root (screen);
+
+      data->end = gnome_bg_create_surface (self->bg, root, width, height, TRUE);
+
+      data->start_time = g_get_real_time () / (double) G_USEC_PER_SEC;
+      data->total_duration = .75;
+      data->is_first_frame = TRUE;
+      data->percent_done = .0;
+
+      data->timeout_id = g_timeout_add (1000 / 60.0, fade_cb, self);
+    }
+  else
+    {
+      g_clear_pointer (&self->surface, cairo_surface_destroy);
+      self->surface = gnome_bg_create_surface (self->bg,
+                                               root,
+                                               width,
+                                               height,
+                                               TRUE);
+
+      gnome_bg_set_surface_as_root (screen, self->surface);
+    }
+
+  g_signal_emit (self, background_signals[READY], 0);
+  gtk_widget_queue_draw (self->window);
+}
+
+typedef struct
+{
+  GfBackground *background;
+  gboolean      fade;
+} ChangeData;
+
+static gboolean
+change_cb (gpointer user_data)
+{
+  ChangeData *data;
+
+  data = (ChangeData *) user_data;
+
+  change (data->background, data->fade);
+  data->background->change_id = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+queue_change (GfBackground *self,
+              gboolean      fade)
+{
+  ChangeData *data;
+
+  if (self->change_id != 0)
+    return;
+
+  data = g_new (ChangeData, 1);
+
+  data->background = self;
+  data->fade = fade;
+
+  self->change_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+                                     change_cb, data, g_free);
+
+  g_source_set_name_by_id (self->change_id, "[gnome-flashback] change_cb");
+}
+
+static gboolean
+draw_cb (GtkWidget    *widget,
+         cairo_t      *cr,
+         GfBackground *self)
+{
+  if (self->fade_data != NULL)
+    {
+      cairo_set_source_surface (cr, self->fade_data->start, 0, 0);
+      cairo_paint (cr);
+
+      cairo_set_source_surface (cr, self->fade_data->end, 0, 0);
+      cairo_paint_with_alpha (cr, self->fade_data->percent_done);
+    }
+  else if (self->surface != NULL)
+    {
+      cairo_set_source_surface (cr, self->surface, 0, 0);
+      cairo_paint (cr);
+    }
+
+  return FALSE;
+}
+
+static void
+size_changed_cb (GfDesktopWindow *window,
+                 GfBackground    *self)
+{
+  queue_change (self, FALSE);
+}
+
+static gboolean
+change_event_cb (GSettings    *settings,
+                 gpointer      keys,
+                 gint          n_keys,
+                 GfBackground *self)
+{
+  gnome_bg_load_from_preferences (self->bg, self->settings1);
+
+  return TRUE;
+}
+
+static void
+changed_cb (GnomeBG      *bg,
+            GfBackground *self)
+{
+  gboolean fade;
+
+  fade = g_settings_get_boolean (self->settings2, "fade");
+  queue_change (self, fade);
+}
+
+static void
+transitioned_cb (GnomeBG      *bg,
+                 GfBackground *self)
+{
+  queue_change (self, FALSE);
+}
+
 static void
 gf_background_constructed (GObject *object)
 {
@@ -61,6 +292,30 @@ gf_background_constructed (GObject *object)
 
   self->settings1 = g_settings_new ("org.gnome.desktop.background");
   self->settings2 = g_settings_new ("org.gnome.gnome-flashback.desktop.background");
+
+  self->bg = gnome_bg_new ();
+
+  g_signal_connect_object (self->window, "draw",
+                           G_CALLBACK (draw_cb),
+                           self, 0);
+
+  g_signal_connect_object (self->window, "size-changed",
+                           G_CALLBACK (size_changed_cb),
+                           self, 0);
+
+  g_signal_connect (self->settings1, "change-event",
+                    G_CALLBACK (change_event_cb),
+                    self);
+
+  g_signal_connect (self->bg, "changed",
+                    G_CALLBACK (changed_cb),
+                    self);
+
+  g_signal_connect (self->bg, "transitioned",
+                    G_CALLBACK (transitioned_cb),
+                    self);
+
+  gnome_bg_load_from_preferences (self->bg, self->settings1);
 }
 
 static void
@@ -72,10 +327,30 @@ gf_background_dispose (GObject *object)
 
   g_clear_object (&self->settings1);
   g_clear_object (&self->settings2);
+  g_clear_object (&self->bg);
 
   G_OBJECT_CLASS (gf_background_parent_class)->dispose (object);
 }
 
+static void
+gf_background_finalize (GObject *object)
+{
+  GfBackground *self;
+
+  self = GF_BACKGROUND (object);
+
+  if (self->change_id != 0)
+    {
+      g_source_remove (self->change_id);
+      self->change_id = 0;
+    }
+
+  g_clear_pointer (&self->fade_data, free_fade_data);
+  g_clear_pointer (&self->surface, cairo_surface_destroy);
+
+  G_OBJECT_CLASS (gf_background_parent_class)->finalize (object);
+}
+
 static void
 gf_background_set_property (GObject      *object,
                             guint         property_id,
@@ -131,6 +406,7 @@ gf_background_class_init (GfBackgroundClass *self_class)
 
   object_class->constructed = gf_background_constructed;
   object_class->dispose = gf_background_dispose;
+  object_class->finalize = gf_background_finalize;
   object_class->set_property = gf_background_set_property;
 
   install_properties (object_class);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]