[evolution] Bug 732180 - Excessive CPU usage due to GtkSpinner



commit 4b213ded59a86df5ddb5e66eec8775d1b93befdd
Author: Milan Crha <mcrha redhat com>
Date:   Fri Jun 27 13:38:39 2014 +0200

    Bug 732180 - Excessive CPU usage due to GtkSpinner
    
    Let's use our own spinner-like widget, which doesn't need as that
    much of CPU as GtkSpinner.

 addressbook/gui/widgets/e-contact-map-window.c |   10 +-
 art/Makefile.am                                |    1 +
 art/working.png                                |  Bin 0 -> 5689 bytes
 e-util/Makefile.am                             |    2 +
 e-util/e-activity-bar.c                        |   13 +-
 e-util/e-activity-proxy.c                      |   14 +-
 e-util/e-spinner.c                             |  253 ++++++++++++++++++++++++
 e-util/e-spinner.h                             |   65 ++++++
 e-util/e-util.h                                |    1 +
 mail/e-mail-config-lookup-page.c               |   14 +-
 10 files changed, 354 insertions(+), 19 deletions(-)
---
diff --git a/addressbook/gui/widgets/e-contact-map-window.c b/addressbook/gui/widgets/e-contact-map-window.c
index b2d13c3..292d5f3 100644
--- a/addressbook/gui/widgets/e-contact-map-window.c
+++ b/addressbook/gui/widgets/e-contact-map-window.c
@@ -17,8 +17,10 @@
  *
  */
 
+#ifdef HAVE_CONFIG_H
 /* This defines WITH_CONTACT_MAPS. */
 #include <config.h>
+#endif
 
 #ifdef WITH_CONTACT_MAPS
 
@@ -186,7 +188,7 @@ contact_map_window_contact_added_cb (EContactMap *map,
 
        window->priv->tasks_cnt--;
        if (window->priv->tasks_cnt == 0) {
-               gtk_spinner_stop (GTK_SPINNER (window->priv->spinner));
+               e_spinner_stop (E_SPINNER (window->priv->spinner));
                gtk_widget_hide (window->priv->spinner);
        }
 }
@@ -230,7 +232,7 @@ contact_map_window_geocoding_started_cb (EContactMap *map,
                                          ClutterActor *marker,
                                          EContactMapWindow *window)
 {
-       gtk_spinner_start (GTK_SPINNER (window->priv->spinner));
+       e_spinner_start (E_SPINNER (window->priv->spinner));
        gtk_widget_show (window->priv->spinner);
 
        window->priv->tasks_cnt++;
@@ -244,7 +246,7 @@ contact_map_window_geocoding_failed_cb (EContactMap *map,
        window->priv->tasks_cnt--;
 
        if (window->priv->tasks_cnt == 0) {
-               gtk_spinner_stop (GTK_SPINNER (window->priv->spinner));
+               e_spinner_stop (E_SPINNER (window->priv->spinner));
                gtk_widget_hide (window->priv->spinner);
        }
 }
@@ -401,7 +403,7 @@ e_contact_map_window_init (EContactMapWindow *window)
        hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 7);
 
        /* Spinner */
-       button = gtk_spinner_new ();
+       button = e_spinner_new ();
        gtk_container_add (GTK_CONTAINER (hbox), button);
        gtk_widget_hide (button);
        priv->spinner = button;
diff --git a/art/Makefile.am b/art/Makefile.am
index 276d435..fec4ed4 100644
--- a/art/Makefile.am
+++ b/art/Makefile.am
@@ -9,6 +9,7 @@ images_DATA = \
        rect.png                        \
        ribbon.jpg                      \
        texture.png                     \
+       working.png                     \
        world_map-960.png
 
 EXTRA_DIST =                           \
diff --git a/art/working.png b/art/working.png
new file mode 100644
index 0000000..3db02dd
Binary files /dev/null and b/art/working.png differ
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 6d9499d..8e91dc8 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -283,6 +283,7 @@ evolution_util_include_HEADERS =  \
        e-spell-dictionary.h \
        e-spell-entry.h \
        e-spell-text-view.h \
+       e-spinner.h \
        e-stock-request.h \
        e-table-click-to-add.h \
        e-table-col-dnd.h \
@@ -555,6 +556,7 @@ libevolution_util_la_SOURCES = \
        e-spell-dictionary.c \
        e-spell-entry.c \
        e-spell-text-view.c \
+       e-spinner.c \
        e-stock-request.c \
        e-table-click-to-add.c \
        e-table-col.c \
diff --git a/e-util/e-activity-bar.c b/e-util/e-activity-bar.c
index 795ece5..e3b0124 100644
--- a/e-util/e-activity-bar.c
+++ b/e-util/e-activity-bar.c
@@ -15,15 +15,18 @@
  *
  */
 
-#include "e-activity-bar.h"
-#include "e-misc-utils.h"
-
+#ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif
 
 #include <glib/gi18n-lib.h>
 #include <libedataserver/libedataserver.h>
 
 #include "e-dialog-widgets.h"
+#include "e-misc-utils.h"
+#include "e-spinner.h"
+
+#include "e-activity-bar.h"
 
 #define E_ACTIVITY_BAR_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -313,8 +316,8 @@ e_activity_bar_init (EActivityBar *bar)
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
        bar->priv->image = widget;
 
-       widget = gtk_spinner_new ();
-       gtk_spinner_start (GTK_SPINNER (widget));
+       widget = e_spinner_new ();
+       e_spinner_start (E_SPINNER (widget));
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
        bar->priv->spinner = widget;
 
diff --git a/e-util/e-activity-proxy.c b/e-util/e-activity-proxy.c
index f3a452b..d0805b2 100644
--- a/e-util/e-activity-proxy.c
+++ b/e-util/e-activity-proxy.c
@@ -18,15 +18,19 @@
  *
  */
 
-#include "e-activity-proxy.h"
-#include "e-misc-utils.h"
-
+#ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif
+
 #include <glib/gi18n.h>
 
 #include <libedataserver/libedataserver.h>
 
 #include "e-dialog-widgets.h"
+#include "e-misc-utils.h"
+#include "e-spinner.h"
+
+#include "e-activity-proxy.h"
 
 #define E_ACTIVITY_PROXY_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -282,8 +286,8 @@ e_activity_proxy_init (EActivityProxy *proxy)
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
        proxy->priv->image = widget;
 
-       widget = gtk_spinner_new ();
-       gtk_spinner_start (GTK_SPINNER (widget));
+       widget = e_spinner_new ();
+       e_spinner_start (E_SPINNER (widget));
        gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 3);
        proxy->priv->spinner = widget;
 
diff --git a/e-util/e-spinner.c b/e-util/e-spinner.c
new file mode 100644
index 0000000..cb4303c
--- /dev/null
+++ b/e-util/e-spinner.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+#include "e-spinner.h"
+
+#define MAIN_IMAGE_FILENAME    "working.png"
+#define FRAME_SIZE             22
+#define FRAME_TIMEOUT_MS       100
+
+struct _ESpinnerPrivate
+{
+       GSList *pixbufs;
+       GSList *current_frame; /* link of 'pixbufs' */
+       gboolean active;
+       guint timeout_id;
+};
+
+enum {
+       PROP_0,
+       PROP_ACTIVE
+};
+
+G_DEFINE_TYPE (ESpinner, e_spinner, GTK_TYPE_IMAGE)
+
+static gboolean
+e_spinner_update_frame_cb (gpointer user_data)
+{
+       ESpinner *spinner = user_data;
+
+       g_return_val_if_fail (E_IS_SPINNER (spinner), FALSE);
+
+       if (spinner->priv->current_frame)
+               spinner->priv->current_frame = spinner->priv->current_frame->next;
+       if (!spinner->priv->current_frame)
+               spinner->priv->current_frame = spinner->priv->pixbufs;
+
+       if (!spinner->priv->current_frame) {
+               g_warn_if_reached ();
+               return FALSE;
+       }
+
+       gtk_image_set_from_pixbuf (GTK_IMAGE (spinner), spinner->priv->current_frame->data);
+
+       return TRUE;
+}
+
+static void
+e_spinner_set_property (GObject *object,
+                       guint property_id,
+                       const GValue *value,
+                       GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_ACTIVE:
+                       e_spinner_set_active (
+                               E_SPINNER (object),
+                               g_value_get_boolean (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_spinner_get_property (GObject *object,
+                       guint property_id,
+                       GValue *value,
+                       GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_ACTIVE:
+                       g_value_set_boolean (
+                               value,
+                               e_spinner_get_active (E_SPINNER (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_spinner_constructed (GObject *object)
+{
+       ESpinner *spinner;
+       GdkPixbuf *main_pixbuf;
+       gint xx, yy, width, height;
+       GError *error = NULL;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_spinner_parent_class)->constructed (object);
+
+       spinner = E_SPINNER (object);
+
+       main_pixbuf = gdk_pixbuf_new_from_file (EVOLUTION_IMAGESDIR G_DIR_SEPARATOR_S MAIN_IMAGE_FILENAME, 
&error);
+       if (!main_pixbuf) {
+               g_warning ("%s: Failed to load image: %s", error ? error->message : "Unknown error", 
G_STRFUNC);
+               g_clear_error (&error);
+               return;
+       }
+
+       width = gdk_pixbuf_get_width (main_pixbuf);
+       height = gdk_pixbuf_get_height (main_pixbuf);
+
+       for (yy = 0; yy < height; yy += FRAME_SIZE) {
+               for (xx = 0; xx < width; xx+= FRAME_SIZE) {
+                       GdkPixbuf *frame;
+
+                       frame = gdk_pixbuf_new_subpixbuf (main_pixbuf, xx, yy, FRAME_SIZE, FRAME_SIZE);
+                       if (frame)
+                               spinner->priv->pixbufs = g_slist_prepend (spinner->priv->pixbufs, frame);
+               }
+       }
+
+       g_object_unref (main_pixbuf);
+
+       spinner->priv->pixbufs = g_slist_reverse (spinner->priv->pixbufs);
+
+       spinner->priv->current_frame = spinner->priv->pixbufs;
+       if (spinner->priv->pixbufs)
+               gtk_image_set_from_pixbuf (GTK_IMAGE (spinner), spinner->priv->pixbufs->data);
+}
+
+static void
+e_spinner_dispose (GObject *object)
+{
+       /* This resets the timeout_id too */
+       e_spinner_set_active (E_SPINNER (object), FALSE);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_spinner_parent_class)->dispose (object);
+}
+
+static void
+e_spinner_finalize (GObject *object)
+{
+       ESpinner *spinner = E_SPINNER (object);
+
+       g_slist_free_full (spinner->priv->pixbufs, g_object_unref);
+       spinner->priv->pixbufs = NULL;
+       spinner->priv->current_frame = NULL;
+
+       g_warn_if_fail (spinner->priv->timeout_id == 0);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_spinner_parent_class)->finalize (object);
+}
+
+static void
+e_spinner_class_init (ESpinnerClass *klass)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (klass, sizeof (ESpinnerPrivate));
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->set_property = e_spinner_set_property;
+       object_class->get_property = e_spinner_get_property;
+       object_class->dispose = e_spinner_dispose;
+       object_class->finalize = e_spinner_finalize;
+       object_class->constructed = e_spinner_constructed;
+
+       /**
+        * ESpinner:active:
+        *
+        * Whether the animation is active.
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_ACTIVE,
+               g_param_spec_boolean (
+                       "active",
+                       "Active",
+                       "Whether the animation is active",
+                       FALSE,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_spinner_init (ESpinner *spinner)
+{
+       spinner->priv = G_TYPE_INSTANCE_GET_PRIVATE (spinner, E_TYPE_SPINNER, ESpinnerPrivate);
+}
+
+GtkWidget *
+e_spinner_new (void)
+{
+       return g_object_new (E_TYPE_SPINNER, NULL);
+}
+
+gboolean
+e_spinner_get_active (ESpinner *spinner)
+{
+       g_return_val_if_fail (E_IS_SPINNER (spinner), FALSE);
+
+       return spinner->priv->active;
+}
+
+void
+e_spinner_set_active (ESpinner *spinner,
+                     gboolean active)
+{
+       g_return_if_fail (E_IS_SPINNER (spinner));
+
+       if ((spinner->priv->active ? 1 : 0) == (active ? 1 : 0))
+               return;
+
+       spinner->priv->active = active;
+
+       if (spinner->priv->timeout_id) {
+               g_source_remove (spinner->priv->timeout_id);
+               spinner->priv->timeout_id = 0;
+       }
+
+       if (spinner->priv->active && spinner->priv->pixbufs)
+               spinner->priv->timeout_id = g_timeout_add_full (G_PRIORITY_LOW, FRAME_TIMEOUT_MS, 
e_spinner_update_frame_cb, spinner, NULL);
+
+       g_object_notify (G_OBJECT (spinner), "active");
+}
+
+void
+e_spinner_start (ESpinner *spinner)
+{
+       e_spinner_set_active (spinner, TRUE);
+}
+
+void
+e_spinner_stop (ESpinner *spinner)
+{
+       e_spinner_set_active (spinner, FALSE);
+}
diff --git a/e-util/e-spinner.h b/e-util/e-spinner.h
new file mode 100644
index 0000000..7fdac37
--- /dev/null
+++ b/e-util/e-spinner.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_SPINNER_H
+#define E_SPINNER_H
+
+#include <gtk/gtk.h>
+
+#define E_TYPE_SPINNER         (e_spinner_get_type ())
+#define E_SPINNER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_SPINNER, ESpinner))
+#define E_SPINNER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_SPINNER, ESpinnerClass))
+#define E_IS_SPINNER(o)                (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_SPINNER))
+#define E_IS_SPINNER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_SPINNER))
+#define E_SPINNER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_TYPE_SPINNER, ESpinnerClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESpinner       ESpinner;
+typedef struct _ESpinnerClass  ESpinnerClass;
+typedef struct _ESpinnerPrivate        ESpinnerPrivate;
+
+struct _ESpinner
+{
+       GtkImage parent;
+
+       /*< private >*/
+       ESpinnerPrivate *priv;
+};
+
+struct _ESpinnerClass
+{
+       GtkImageClass parent_class;
+};
+
+GType          e_spinner_get_type      (void);
+
+GtkWidget *    e_spinner_new           (void);
+gboolean       e_spinner_get_active    (ESpinner *spinner);
+void           e_spinner_set_active    (ESpinner *spinner,
+                                        gboolean active);
+void           e_spinner_start         (ESpinner *spinner);
+void           e_spinner_stop          (ESpinner *spinner);
+
+G_END_DECLS
+
+#endif /* E_SPINNER_H */
diff --git a/e-util/e-util.h b/e-util/e-util.h
index e9b06fe..e2481eb 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -194,6 +194,7 @@
 #include <e-util/e-source-util.h>
 #include <e-util/e-spell-entry.h>
 #include <e-util/e-spell-text-view.h>
+#include <e-util/e-spinner.h>
 #include <e-util/e-stock-request.h>
 #include <e-util/e-table-click-to-add.h>
 #include <e-util/e-table-col-dnd.h>
diff --git a/mail/e-mail-config-lookup-page.c b/mail/e-mail-config-lookup-page.c
index 8986469..4ef4fee 100644
--- a/mail/e-mail-config-lookup-page.c
+++ b/mail/e-mail-config-lookup-page.c
@@ -14,12 +14,16 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  */
-
-#include "e-mail-config-lookup-page.h"
-
+#ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif
+
 #include <glib/gi18n-lib.h>
 
+#include "e-util/e-util.h"
+
+#include "e-mail-config-lookup-page.h"
+
 /* Forward Declarations */
 static void    e_mail_config_lookup_page_interface_init
                                        (EMailConfigPageInterface *iface);
@@ -59,8 +63,8 @@ mail_config_lookup_page_constructed (GObject *object)
 
        container = widget;
 
-       widget = gtk_spinner_new ();
-       gtk_spinner_start (GTK_SPINNER (widget));
+       widget = e_spinner_new ();
+       e_spinner_start (E_SPINNER (widget));
        gtk_container_add (GTK_CONTAINER (container), widget);
        gtk_widget_show (widget);
 


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