diff options
author | Milan Crha <mcrha@redhat.com> | 2014-06-27 19:38:39 +0800 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2014-06-27 19:38:39 +0800 |
commit | 4b213ded59a86df5ddb5e66eec8775d1b93befdd (patch) | |
tree | 324974669d85fb38224d7db22a3dd09daf634ef8 /e-util | |
parent | 586ab6e32a64e18b78607b3300e82181ee3b11ff (diff) | |
download | gsoc2013-evolution-4b213ded59a86df5ddb5e66eec8775d1b93befdd.tar gsoc2013-evolution-4b213ded59a86df5ddb5e66eec8775d1b93befdd.tar.gz gsoc2013-evolution-4b213ded59a86df5ddb5e66eec8775d1b93befdd.tar.bz2 gsoc2013-evolution-4b213ded59a86df5ddb5e66eec8775d1b93befdd.tar.lz gsoc2013-evolution-4b213ded59a86df5ddb5e66eec8775d1b93befdd.tar.xz gsoc2013-evolution-4b213ded59a86df5ddb5e66eec8775d1b93befdd.tar.zst gsoc2013-evolution-4b213ded59a86df5ddb5e66eec8775d1b93befdd.zip |
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.
Diffstat (limited to 'e-util')
-rw-r--r-- | e-util/Makefile.am | 2 | ||||
-rw-r--r-- | e-util/e-activity-bar.c | 13 | ||||
-rw-r--r-- | e-util/e-activity-proxy.c | 14 | ||||
-rw-r--r-- | e-util/e-spinner.c | 253 | ||||
-rw-r--r-- | e-util/e-spinner.h | 65 | ||||
-rw-r--r-- | e-util/e-util.h | 1 |
6 files changed, 338 insertions, 10 deletions
diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 6d9499db27..8e91dc8068 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 795ece505c..e3b0124913 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 f3a452b5af..d0805b2f57 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 0000000000..cb4303c467 --- /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 0000000000..7fdac372dd --- /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 e9b06fe27c..e2481eb5de 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> |