summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2009-07-21 02:16:56 +0100
committerBastien Nocera <hadess@hadess.net>2009-10-14 14:58:30 +0100
commitd21700f5105c2e4b215aa2b4d4f8c90121748cda (patch)
treeb03eb0b607309e6eb10b92c97bd333d0485f79b3
parentdf53e6ad8b8939f1e7bb9a48987f972fec6cfa4c (diff)
downloadgtk+-d21700f5105c2e4b215aa2b4d4f8c90121748cda.tar.gz
Bug 319607 – Add a throbber (activity widget) to GTK+
Add GtkSpinner activity throbber, as well as a cell renderer.
-rw-r--r--demos/gtk-demo/Makefile.am1
-rw-r--r--demos/gtk-demo/list_store.c144
-rw-r--r--demos/gtk-demo/spinner.c90
-rw-r--r--docs/reference/gtk/gtk-sections.txt36
-rw-r--r--gtk/Makefile.am4
-rw-r--r--gtk/gtk.h2
-rw-r--r--gtk/gtk.symbols17
-rw-r--r--gtk/gtkcellrendererspinner.c362
-rw-r--r--gtk/gtkcellrendererspinner.h60
-rw-r--r--gtk/gtkspinner.c525
-rw-r--r--gtk/gtkspinner.h65
-rw-r--r--gtk/gtkstyle.c118
-rw-r--r--gtk/gtkstyle.h18
13 files changed, 1403 insertions, 39 deletions
diff --git a/demos/gtk-demo/Makefile.am b/demos/gtk-demo/Makefile.am
index b2d856856f..45d3ef3643 100644
--- a/demos/gtk-demo/Makefile.am
+++ b/demos/gtk-demo/Makefile.am
@@ -37,6 +37,7 @@ demos = \
rotated_text.c \
search_entry.c \
sizegroup.c \
+ spinner.c \
stock_browser.c \
textview.c \
textscroll.c \
diff --git a/demos/gtk-demo/list_store.c b/demos/gtk-demo/list_store.c
index 990e489921..33a7189559 100644
--- a/demos/gtk-demo/list_store.c
+++ b/demos/gtk-demo/list_store.c
@@ -10,6 +10,8 @@
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
+static GtkTreeModel *model = NULL;
+static guint timeout = 0;
typedef struct
{
@@ -26,6 +28,8 @@ enum
COLUMN_NUMBER,
COLUMN_SEVERITY,
COLUMN_DESCRIPTION,
+ COLUMN_PULSE,
+ COLUMN_ACTIVE,
NUM_COLUMNS
};
@@ -47,6 +51,33 @@ static Bug data[] =
{ FALSE, 1, "Normal", "First bug :=)" },
};
+static gboolean
+spinner_timeout (gpointer data)
+{
+ GtkTreeIter iter;
+ guint pulse;
+
+ if (model == NULL)
+ return FALSE;
+
+ gtk_tree_model_get_iter_first (model, &iter);
+ gtk_tree_model_get (model, &iter,
+ COLUMN_PULSE, &pulse,
+ -1);
+ if (pulse == G_MAXUINT)
+ pulse = 0;
+ else
+ pulse++;
+
+ gtk_list_store_set (GTK_LIST_STORE (model),
+ &iter,
+ COLUMN_PULSE, pulse,
+ COLUMN_ACTIVE, TRUE,
+ -1);
+
+ return TRUE;
+}
+
static GtkTreeModel *
create_model (void)
{
@@ -56,21 +87,25 @@ create_model (void)
/* create list store */
store = gtk_list_store_new (NUM_COLUMNS,
- G_TYPE_BOOLEAN,
- G_TYPE_UINT,
- G_TYPE_STRING,
- G_TYPE_STRING);
+ G_TYPE_BOOLEAN,
+ G_TYPE_UINT,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_UINT,
+ G_TYPE_BOOLEAN);
/* add data to the list store */
for (i = 0; i < G_N_ELEMENTS (data); i++)
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
- COLUMN_FIXED, data[i].fixed,
- COLUMN_NUMBER, data[i].number,
- COLUMN_SEVERITY, data[i].severity,
- COLUMN_DESCRIPTION, data[i].description,
- -1);
+ COLUMN_FIXED, data[i].fixed,
+ COLUMN_NUMBER, data[i].number,
+ COLUMN_SEVERITY, data[i].severity,
+ COLUMN_DESCRIPTION, data[i].description,
+ COLUMN_PULSE, 0,
+ COLUMN_ACTIVE, FALSE,
+ -1);
}
return GTK_TREE_MODEL (store);
@@ -78,8 +113,8 @@ create_model (void)
static void
fixed_toggled (GtkCellRendererToggle *cell,
- gchar *path_str,
- gpointer data)
+ gchar *path_str,
+ gpointer data)
{
GtkTreeModel *model = (GtkTreeModel *)data;
GtkTreeIter iter;
@@ -110,48 +145,75 @@ add_columns (GtkTreeView *treeview)
/* column for fixed toggles */
renderer = gtk_cell_renderer_toggle_new ();
g_signal_connect (renderer, "toggled",
- G_CALLBACK (fixed_toggled), model);
+ G_CALLBACK (fixed_toggled), model);
column = gtk_tree_view_column_new_with_attributes ("Fixed?",
- renderer,
- "active", COLUMN_FIXED,
- NULL);
+ renderer,
+ "active", COLUMN_FIXED,
+ NULL);
/* set this column to a fixed sizing (of 50 pixels) */
gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
- GTK_TREE_VIEW_COLUMN_FIXED);
+ GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50);
gtk_tree_view_append_column (treeview, column);
/* column for bug numbers */
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Bug number",
- renderer,
- "text",
- COLUMN_NUMBER,
- NULL);
+ renderer,
+ "text",
+ COLUMN_NUMBER,
+ NULL);
gtk_tree_view_column_set_sort_column_id (column, COLUMN_NUMBER);
gtk_tree_view_append_column (treeview, column);
/* column for severities */
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Severity",
- renderer,
- "text",
- COLUMN_SEVERITY,
- NULL);
+ renderer,
+ "text",
+ COLUMN_SEVERITY,
+ NULL);
gtk_tree_view_column_set_sort_column_id (column, COLUMN_SEVERITY);
gtk_tree_view_append_column (treeview, column);
/* column for description */
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes ("Description",
- renderer,
- "text",
- COLUMN_DESCRIPTION,
- NULL);
+ renderer,
+ "text",
+ COLUMN_DESCRIPTION,
+ NULL);
gtk_tree_view_column_set_sort_column_id (column, COLUMN_DESCRIPTION);
gtk_tree_view_append_column (treeview, column);
+
+ /* column for spinner */
+ renderer = gtk_cell_renderer_spinner_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Spinning",
+ renderer,
+ "pulse",
+ COLUMN_PULSE,
+ "active",
+ COLUMN_ACTIVE,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_PULSE);
+ gtk_tree_view_append_column (treeview, column);
+}
+
+static gboolean
+window_closed (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ model = NULL;
+ window = NULL;
+ if (timeout != 0)
+ {
+ g_source_remove (timeout);
+ timeout = 0;
+ }
+ return FALSE;
}
GtkWidget *
@@ -162,17 +224,16 @@ do_list_store (GtkWidget *do_widget)
GtkWidget *vbox;
GtkWidget *label;
GtkWidget *sw;
- GtkTreeModel *model;
GtkWidget *treeview;
/* create window, etc */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_screen (GTK_WINDOW (window),
- gtk_widget_get_screen (do_widget));
+ gtk_widget_get_screen (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "GtkListStore demo");
g_signal_connect (window, "destroy",
- G_CALLBACK (gtk_widget_destroyed), &window);
+ G_CALLBACK (gtk_widget_destroyed), &window);
gtk_container_set_border_width (GTK_CONTAINER (window), 8);
vbox = gtk_vbox_new (FALSE, 8);
@@ -183,10 +244,10 @@ do_list_store (GtkWidget *do_widget)
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
- GTK_SHADOW_ETCHED_IN);
+ GTK_SHADOW_ETCHED_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
- GTK_POLICY_NEVER,
- GTK_POLICY_AUTOMATIC);
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
/* create tree model */
@@ -196,7 +257,7 @@ do_list_store (GtkWidget *do_widget)
treeview = gtk_tree_view_new_with_model (model);
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview),
- COLUMN_DESCRIPTION);
+ COLUMN_DESCRIPTION);
g_object_unref (model);
@@ -207,14 +268,25 @@ do_list_store (GtkWidget *do_widget)
/* finish & show */
gtk_window_set_default_size (GTK_WINDOW (window), 280, 250);
+ g_signal_connect (window, "delete-event",
+ G_CALLBACK (window_closed), NULL);
}
if (!GTK_WIDGET_VISIBLE (window))
- gtk_widget_show_all (window);
+ {
+ gtk_widget_show_all (window);
+ if (timeout == 0)
+ timeout = g_timeout_add (80, spinner_timeout, NULL);
+ }
else
{
gtk_widget_destroy (window);
window = NULL;
+ if (timeout != 0)
+ {
+ g_source_remove (timeout);
+ timeout = 0;
+ }
}
return window;
diff --git a/demos/gtk-demo/spinner.c b/demos/gtk-demo/spinner.c
new file mode 100644
index 0000000000..f18e1a17eb
--- /dev/null
+++ b/demos/gtk-demo/spinner.c
@@ -0,0 +1,90 @@
+/* Spinner
+ *
+ * GtkSpinner allows to show that background activity is on-going.
+ *
+ */
+
+#include <gtk/gtk.h>
+
+static GtkWidget *window = NULL;
+static GtkWidget *spinner_sensitive = NULL;
+static GtkWidget *spinner_unsensitive = NULL;
+
+static void
+on_play_clicked (GtkButton *button, gpointer user_data)
+{
+ gtk_spinner_start (GTK_SPINNER (spinner_sensitive));
+ gtk_spinner_start (GTK_SPINNER (spinner_unsensitive));
+}
+
+static void
+on_stop_clicked (GtkButton *button, gpointer user_data)
+{
+ gtk_spinner_stop (GTK_SPINNER (spinner_sensitive));
+ gtk_spinner_stop (GTK_SPINNER (spinner_unsensitive));
+}
+
+GtkWidget *
+do_spinner (GtkWidget *do_widget)
+{
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *button;
+ GtkWidget *spinner;
+
+ if (!window)
+ {
+ window = gtk_dialog_new_with_buttons ("GtkSpinner",
+ GTK_WINDOW (do_widget),
+ 0,
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_NONE,
+ NULL);
+ gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+
+ g_signal_connect (window, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gtk_widget_destroyed), &window);
+
+ vbox = gtk_vbox_new (FALSE, 5);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
+
+ /* Sensitive */
+ hbox = gtk_hbox_new (FALSE, 5);
+ spinner = gtk_spinner_new ();
+ gtk_container_add (GTK_CONTAINER (hbox), spinner);
+ gtk_container_add (GTK_CONTAINER (hbox), gtk_entry_new ());
+ gtk_container_add (GTK_CONTAINER (vbox), hbox);
+ spinner_sensitive = spinner;
+
+ /* Disabled */
+ hbox = gtk_hbox_new (FALSE, 5);
+ spinner = gtk_spinner_new ();
+ gtk_container_add (GTK_CONTAINER (hbox), spinner);
+ gtk_container_add (GTK_CONTAINER (hbox), gtk_entry_new ());
+ gtk_container_add (GTK_CONTAINER (vbox), hbox);
+ spinner_unsensitive = spinner;
+ gtk_widget_set_sensitive (hbox, FALSE);
+
+ button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (on_play_clicked), spinner);
+ gtk_container_add (GTK_CONTAINER (vbox), button);
+
+ button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_STOP);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (on_stop_clicked), spinner);
+ gtk_container_add (GTK_CONTAINER (vbox), button);
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show_all (window);
+ else
+ gtk_widget_destroy (window);
+
+ return window;
+}
+
+
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index ed91762e00..a06e5b593a 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -3585,6 +3585,24 @@ gtk_spin_button_get_type
</SECTION>
<SECTION>
+<FILE>gtkspinner</FILE>
+<TITLE>GtkSpinner</TITLE>
+GtkSpinner
+gtk_spinner_new
+gtk_spinner_start
+gtk_spinner_stop
+<SUBSECTION Standard>
+GTK_SPINNER
+GTK_IS_SPINNER
+GTK_TYPE_SPINNER
+GTK_SPINNER_CLASS
+GTK_IS_SPINER_CLASS
+GTK_SPINNER_GET_CLASS
+<SUBSECTION Private>
+gtk_spinner_get_type
+</SECTION>
+
+<SECTION>
<FILE>gtkstatusbar</FILE>
<TITLE>GtkStatusbar</TITLE>
GtkStatusbar
@@ -5107,6 +5125,23 @@ gtk_cell_renderer_spin_get_type
</SECTION>
<SECTION>
+<FILE>gtkcellrendererspinner</FILE>
+<TITLE>GtkCellRendererSpinner</TITLE>
+GtkCellRendererSpinner
+gtk_cell_renderer_spinner_new
+<SUBSECTION Standard>
+GTK_TYPE_CELL_RENDERER_SPINNER
+GTK_CELL_RENDERER_SPINNER
+GTK_CELL_RENDERER_SPINNER_CLASS
+GTK_IS_CELL_RENDERER_SPINNER
+GTK_IS_CELL_RENDERER_SPINNER_CLASS
+GTK_CELL_RENDERER_SPINNER_GET_CLASS
+<SUBSECTION Private>
+GtkCellRendererSpinnerPrivate
+gtk_cell_renderer_spinner_get_type
+</SECTION>
+
+<SECTION>
<FILE>gtkcellrendererpixbuf</FILE>
<TITLE>GtkCellRendererPixbuf</TITLE>
GtkCellRendererPixbuf
@@ -5929,6 +5964,7 @@ gtk_paint_polygon
gtk_paint_shadow
gtk_paint_shadow_gap
gtk_paint_slider
+gtk_paint_spinner
gtk_paint_string
gtk_paint_tab
gtk_paint_vline
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index b6e32cf6a9..94f27ae0ea 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -178,6 +178,7 @@ gtk_public_h_sources = \
gtkcellrendererpixbuf.h \
gtkcellrendererprogress.h \
gtkcellrendererspin.h \
+ gtkcellrendererspinner.h\
gtkcellrenderertext.h \
gtkcellrenderertoggle.h \
gtkcellview.h \
@@ -289,6 +290,7 @@ gtk_public_h_sources = \
gtksizegroup.h \
gtksocket.h \
gtkspinbutton.h \
+ gtkspinner.h \
gtkstatusbar.h \
gtkstatusicon.h \
gtkstock.h \
@@ -433,6 +435,7 @@ gtk_base_c_sources = \
gtkcellrendererpixbuf.c \
gtkcellrendererprogress.c \
gtkcellrendererspin.c \
+ gtkcellrendererspinner.c\
gtkcellrenderertext.c \
gtkcellrenderertoggle.c \
gtkcellview.c \
@@ -557,6 +560,7 @@ gtk_base_c_sources = \
gtkshow.c \
gtksocket.c \
gtkspinbutton.c \
+ gtkspinner.c \
gtkstatusbar.c \
gtkstatusicon.c \
gtkstock.c \
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 211c2d253a..6cf26a3ee4 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -59,6 +59,7 @@
#include <gtk/gtkcellrendererpixbuf.h>
#include <gtk/gtkcellrendererprogress.h>
#include <gtk/gtkcellrendererspin.h>
+#include <gtk/gtkcellrendererspinner.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtkcellrenderertoggle.h>
#include <gtk/gtkcellview.h>
@@ -168,6 +169,7 @@
#include <gtk/gtksizegroup.h>
#include <gtk/gtksocket.h>
#include <gtk/gtkspinbutton.h>
+#include <gtk/gtkspinner.h>
#include <gtk/gtkstatusbar.h>
#include <gtk/gtkstatusicon.h>
#include <gtk/gtkstock.h>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 721239f52f..c3952a4673 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -670,6 +670,13 @@ gtk_cell_renderer_spin_new
#endif
#endif
+#if IN_HEADER(__GTK_CELL_RENDERER_SPINNER_H__)
+#if IN_FILE(__GTK_CELL_RENDERER_SPINNER_C__)
+gtk_cell_renderer_spinner_get_type G_GNUC_CONST
+gtk_cell_renderer_spinner_new
+#endif
+#endif
+
#if IN_HEADER(__GTK_CELL_RENDERER_PROGRESS_H__)
#if IN_FILE(__GTK_CELL_RENDERER_PROGRESS_C__)
gtk_cell_renderer_progress_get_type G_GNUC_CONST
@@ -1277,6 +1284,7 @@ gtk_paint_resize_grip
gtk_paint_shadow
gtk_paint_shadow_gap
gtk_paint_slider
+gtk_paint_spinner
gtk_paint_tab
gtk_paint_vline
gtk_border_new G_GNUC_MALLOC
@@ -3802,6 +3810,15 @@ gtk_spin_button_update
#endif
#endif
+#if IN_HEADER(__GTK_SPINNER_H__)
+#if IN_FILE(__GTK_SPINNER_C__)
+gtk_spinner_get_type G_GNUC_CONST
+gtk_spinner_new
+gtk_spinner_start
+gtk_spinner_stop
+#endif
+#endif
+
#if IN_HEADER(__GTK_STATUSBAR_H__)
#if IN_FILE(__GTK_STATUSBAR_C__)
gtk_statusbar_get_context_id
diff --git a/gtk/gtkcellrendererspinner.c b/gtk/gtkcellrendererspinner.c
new file mode 100644
index 0000000000..6501b267c8
--- /dev/null
+++ b/gtk/gtkcellrendererspinner.c
@@ -0,0 +1,362 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2009 Matthias Clasen <mclasen@redhat.com>
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+ *
+ * This library 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; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 2007. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gtkintl.h"
+#include <gtk/gtk.h>
+#include "gtkcellrendererspinner.h"
+#include "gtkalias.h"
+
+enum {
+ PROP_0,
+ PROP_ACTIVE,
+ PROP_PULSE,
+ PROP_SIZE
+};
+
+struct _GtkCellRendererSpinnerPrivate
+{
+ gboolean active;
+ guint pulse;
+ GtkIconSize icon_size, old_icon_size;
+ gint size;
+};
+
+#define GTK_CELL_RENDERER_SPINNER_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
+ GTK_TYPE_CELL_RENDERER_SPINNER, \
+ GtkCellRendererSpinnerPrivate))
+
+static void gtk_cell_renderer_spinner_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gtk_cell_renderer_spinner_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gtk_cell_renderer_spinner_get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height);
+static void gtk_cell_renderer_spinner_render (GtkCellRenderer *cell,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ guint flags);
+
+G_DEFINE_TYPE (GtkCellRendererSpinner, gtk_cell_renderer_spinner, GTK_TYPE_CELL_RENDERER)
+
+static void
+gtk_cell_renderer_spinner_class_init (GtkCellRendererSpinnerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
+
+ object_class->get_property = gtk_cell_renderer_spinner_get_property;
+ object_class->set_property = gtk_cell_renderer_spinner_set_property;
+
+ cell_class->get_size = gtk_cell_renderer_spinner_get_size;
+ cell_class->render = gtk_cell_renderer_spinner_render;
+
+ /* GtkCellRendererSpinner::active:
+ *
+ * Whether the spinner is active (ie. shown) in the cell
+ *
+ * Since 2.20
+ */
+ g_object_class_install_property (object_class,
+ PROP_ACTIVE,
+ g_param_spec_boolean ("active",
+ P_("Active"),
+ P_("Whether the spinner is active (ie. shown) in the cell"),
+ FALSE,
+ G_PARAM_READWRITE));
+ /* GtkCellRendererSpinner::pulse:
+ *
+ * Pulse of the spinner. Increment this value to draw the next frame of the spinner animation.
+ * Usually, you would update this value in a timeout, every 80 milliseconds to show a full
+ * animation within one second.
+ *
+ * Since 2.20
+ */
+ g_object_class_install_property (object_class,
+ PROP_PULSE,
+ g_param_spec_uint ("pulse",
+ P_("Pulse"),
+ P_("Pulse of the spinner"),
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE));
+ /* GtkCellRendererSpinner::size:
+ *
+ * The #GtkIconSize value that specifies the size of the rendered spinner.
+ *
+ * Since 2.20
+ */
+ g_object_class_install_property (object_class,
+ PROP_SIZE,
+ g_param_spec_enum ("size",
+ P_("Size"),
+ P_("The #GtkIconSize value that specifies the size of the rendered spinner"),
+ GTK_TYPE_ICON_SIZE, GTK_ICON_SIZE_MENU,
+ G_PARAM_READWRITE));
+
+
+ g_type_class_add_private (object_class, sizeof (GtkCellRendererSpinnerPrivate));
+}
+
+static void
+gtk_cell_renderer_spinner_init (GtkCellRendererSpinner *cell)
+{
+ cell->priv = GTK_CELL_RENDERER_SPINNER_GET_PRIVATE (cell);
+ cell->priv->pulse = 0;
+ cell->priv->old_icon_size = GTK_ICON_SIZE_INVALID;
+ cell->priv->icon_size = GTK_ICON_SIZE_MENU;
+}
+
+/**
+ * gtk_cell_renderer_spinner_new
+ *
+ * Returns a new cell renderer which will show a spinner to indicate
+ * activity.
+ *
+ * Return value: a new #GtkCellRenderer
+ *
+ * Since: 2.20
+ */
+GtkCellRenderer *
+gtk_cell_renderer_spinner_new (void)
+{
+ return g_object_new (GTK_TYPE_CELL_RENDERER_SPINNER, NULL);
+}
+
+static void
+gtk_cell_renderer_spinner_update_size (GtkCellRendererSpinner *cell,
+ GtkWidget *widget)
+{
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+ GdkScreen *screen;
+ GtkIconTheme *icon_theme;
+ GtkSettings *settings;
+
+ if (cell->priv->old_icon_size == cell->priv->icon_size)
+ return;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (widget));
+ icon_theme = gtk_icon_theme_get_for_screen (screen);
+ settings = gtk_settings_get_for_screen (screen);
+
+ if (!gtk_icon_size_lookup_for_settings (settings, priv->icon_size, &priv->size, NULL))
+ {
+ g_warning ("Invalid icon size %u\n", priv->icon_size);
+ priv->size = 24;
+ }
+}
+
+static void
+gtk_cell_renderer_spinner_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (object);
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+
+ switch (param_id)
+ {
+ case PROP_ACTIVE:
+ g_value_set_boolean (value, priv->active);
+ break;
+ case PROP_PULSE:
+ g_value_set_uint (value, priv->pulse);
+ break;
+ case PROP_SIZE:
+ g_value_set_enum (value, priv->icon_size);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static void
+gtk_cell_renderer_spinner_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (object);
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+
+ switch (param_id)
+ {
+ case PROP_ACTIVE:
+ priv->active = g_value_get_boolean (value);
+ break;
+ case PROP_PULSE:
+ priv->pulse = g_value_get_uint (value);
+ break;
+ case PROP_SIZE:
+ priv->old_icon_size = priv->icon_size;
+ priv->icon_size = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static void
+gtk_cell_renderer_spinner_get_size (GtkCellRenderer *cellr,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height)
+{
+ GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (cellr);
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+ gdouble align;
+ gint w, h;
+ gint xpad, ypad;
+ gfloat xalign, yalign;
+ gboolean rtl;
+
+ rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+
+ gtk_cell_renderer_spinner_update_size (cell, widget);
+
+ g_object_get (cellr,
+ "xpad", &xpad,
+ "ypad", &ypad,
+ "xalign", &xalign,
+ "yalign", &yalign,
+ NULL);
+ w = h = priv->size;
+
+ if (cell_area)
+ {
+ if (x_offset)
+ {
+ align = rtl ? 1.0 - xalign : xalign;
+ *x_offset = align * (cell_area->width - w);
+ *x_offset = MAX (*x_offset, 0);
+ }
+ if (y_offset)
+ {
+ align = rtl ? 1.0 - yalign : yalign;
+ *y_offset = align * (cell_area->height - h);
+ *y_offset = MAX (*y_offset, 0);
+ }
+ }
+ else
+ {
+ if (x_offset)
+ *x_offset = 0;
+ if (y_offset)
+ *y_offset = 0;
+ }
+
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+}
+
+static void
+gtk_cell_renderer_spinner_render (GtkCellRenderer *cellr,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ guint flags)
+{
+ GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (cellr);
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+ GtkStateType state;
+ GdkRectangle pix_rect;
+ GdkRectangle draw_rect;
+ gint xpad, ypad;
+
+ if (!priv->active)
+ return;
+
+ gtk_cell_renderer_spinner_get_size (cellr, widget, cell_area,
+ &pix_rect.x, &pix_rect.y,
+ &pix_rect.width, &pix_rect.height);
+
+ g_object_get (cellr,
+ "xpad", &xpad,
+ "ypad", &ypad,
+ NULL);
+ pix_rect.x += cell_area->x + xpad;
+ pix_rect.y += cell_area->y + ypad;
+ pix_rect.width -= xpad * 2;
+ pix_rect.height -= ypad * 2;
+
+ if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) ||
+ !gdk_rectangle_intersect (expose_area, &pix_rect, &draw_rect))
+ {
+ return;
+ }
+
+ state = GTK_STATE_NORMAL;
+ if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE || !cellr->sensitive)
+ {
+ state = GTK_STATE_INSENSITIVE;
+ }
+ else
+ {
+ if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
+ {
+ if (GTK_WIDGET_HAS_FOCUS (widget))
+ state = GTK_STATE_SELECTED;
+ else
+ state = GTK_STATE_ACTIVE;
+ }
+ else
+ state = GTK_STATE_PRELIGHT;
+ }
+
+ gtk_paint_spinner (widget->style,
+ window,
+ state,
+ priv->pulse,
+ draw_rect.x, draw_rect.y,
+ draw_rect.width, draw_rect.height);
+}
+
+#define __GTK_CELL_RENDERER_SPINNER_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkcellrendererspinner.h b/gtk/gtkcellrendererspinner.h
new file mode 100644
index 0000000000..bd0ce14717
--- /dev/null
+++ b/gtk/gtkcellrendererspinner.h
@@ -0,0 +1,60 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2009 Matthias Clasen <mclasen@redhat.com>
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+ *
+ * This library 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; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_CELL_RENDERER_SPINNER_H__
+#define __GTK_CELL_RENDERER_SPINNER_H__
+
+#include <gtk/gtk.h>
+
+#define GTK_TYPE_CELL_RENDERER_SPINNER (gtk_cell_renderer_spinner_get_type ())
+#define GTK_CELL_RENDERER_SPINNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_RENDERER_SPINNER, GtkCellRendererSpinner))
+#define GTK_CELL_RENDERER_SPINNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CELL_RENDERER_SPINNER, GtkCellRendererSpinnerClass))
+#define GTK_IS_CELL_RENDERER_SPINNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_RENDERER_SPINNER))
+#define GTK_IS_CELL_RENDERER_SPINNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CELL_RENDERER_SPINNER))
+#define GTK_CELL_RENDERER_SPINNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CELL_RENDERER_SPINNER, GtkCellRendererSpinnerClass))
+
+typedef struct _GtkCellRendererSpinner GtkCellRendererSpinner;
+typedef struct _GtkCellRendererSpinnerClass GtkCellRendererSpinnerClass;
+typedef struct _GtkCellRendererSpinnerPrivate GtkCellRendererSpinnerPrivate;
+
+struct _GtkCellRendererSpinner
+{
+ GtkCellRenderer parent;
+ GtkCellRendererSpinnerPrivate *priv;
+};
+
+struct _GtkCellRendererSpinnerClass
+{
+ GtkCellRendererClass parent_class;
+
+ /* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
+ void (*_gtk_reserved2) (void);
+ void (*_gtk_reserved3) (void);
+ void (*_gtk_reserved4) (void);
+};
+
+GType gtk_cell_renderer_spinner_get_type (void) G_GNUC_CONST;
+GtkCellRenderer *gtk_cell_renderer_spinner_new (void);
+
+#endif /* __GTK_CELL_RENDERER_SPINNER_H__ */
+
diff --git a/gtk/gtkspinner.c b/gtk/gtkspinner.c
new file mode 100644
index 0000000000..c79e14e570
--- /dev/null
+++ b/gtk/gtkspinner.c
@@ -0,0 +1,525 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2007 John Stowers, Neil Jagdish Patel.
+ * Copyright (C) 2009 Bastien Nocera, David Zeuthen
+ *
+ * This library 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; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Code adapted from egg-spinner
+ * by Christian Hergert <christian.hergert@gmail.com>
+ */
+
+/*
+ * Modified by the GTK+ Team and others 2007. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gtkintl.h"
+#include "gtkaccessible.h"
+#include "gtkimage.h"
+#include "gtkspinner.h"
+#include "gtkstyle.h"
+#include "gtkalias.h"
+
+#define GTK_SPINNER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SPINNER, GtkSpinnerPrivate))
+
+G_DEFINE_TYPE (GtkSpinner, gtk_spinner, GTK_TYPE_DRAWING_AREA);
+
+enum {
+ PROP_0,
+ PROP_ACTIVE
+};
+
+struct _GtkSpinnerPrivate
+{
+ guint current;
+ guint num_steps;
+ guint timeout;
+};
+
+static void gtk_spinner_class_init (GtkSpinnerClass *klass);
+static void gtk_spinner_init (GtkSpinner *spinner);
+static void gtk_spinner_dispose (GObject *gobject);
+static gboolean gtk_spinner_expose (GtkWidget *widget, GdkEventExpose *event);
+static void gtk_spinner_screen_changed (GtkWidget* widget, GdkScreen* old_screen);
+static void gtk_spinner_style_set (GtkWidget *widget, GtkStyle *prev_style);
+static void gtk_spinner_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gtk_spinner_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static AtkObject *gtk_spinner_get_accessible (GtkWidget *widget);
+static GType gtk_spinner_accessible_get_type (void);
+
+static void
+gtk_spinner_class_init (GtkSpinnerClass *klass)
+{
+ GObjectClass *gobject_class;
+ GtkWidgetClass *widget_class;
+
+ gtk_spinner_parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class = G_OBJECT_CLASS(klass);
+ g_type_class_add_private (gobject_class, sizeof (GtkSpinnerPrivate));
+ gobject_class->dispose = gtk_spinner_dispose;
+ gobject_class->get_property = gtk_spinner_get_property;
+ gobject_class->set_property = gtk_spinner_set_property;
+
+ widget_class = GTK_WIDGET_CLASS(klass);
+ widget_class->expose_event = gtk_spinner_expose;
+ widget_class->screen_changed = gtk_spinner_screen_changed;
+ widget_class->style_set = gtk_spinner_style_set;
+ widget_class->get_accessible = gtk_spinner_get_accessible;
+
+ /* GtkSpinner::active:
+ *
+ * Whether the spinner is active
+ *
+ * Since 2.20
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ACTIVE,
+ g_param_spec_boolean ("active",
+ P_("Active"),
+ P_("Whether the spinner is active"),
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * GtkSpinner::num-steps:
+ *
+ * The number of steps for the spinner to complete a full loop. The animation will
+ * complete a full revolution in one second.
+ *
+ * Since: 2.20
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_uint ("num-steps",
+ P_("Number of steps"),
+ P_("The number of steps for the spinner to complete a full loop. The animation will complete a full revolution in one second."),
+ 1,
+ G_MAXUINT,
+ 12,
+ G_PARAM_READABLE));
+}
+
+static void
+gtk_spinner_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER_GET_PRIVATE (object);
+
+ switch (param_id)
+ {
+ case PROP_ACTIVE:
+ g_value_set_boolean (value, priv->timeout != 0);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static void
+gtk_spinner_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (param_id)
+ {
+ case PROP_ACTIVE:
+ gtk_spinner_start (GTK_SPINNER (object));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static void
+gtk_spinner_init (GtkSpinner *spinner)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER_GET_PRIVATE (spinner);
+ priv->current = 0;
+ priv->timeout = 0;
+
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET (spinner), GTK_NO_WINDOW);
+}
+
+static gboolean
+gtk_spinner_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+ GtkStateType state_type;
+ GtkSpinnerPrivate *priv;
+ int width, height;
+
+ priv = GTK_SPINNER_GET_PRIVATE (widget);
+
+ width = widget->allocation.width;
+ height = widget->allocation.height;
+
+ if ((width < 12) || (height <12))
+ gtk_widget_set_size_request (widget, 12, 12);
+
+ state_type = GTK_STATE_NORMAL;
+ if (!GTK_WIDGET_IS_SENSITIVE (widget))
+ state_type = GTK_STATE_INSENSITIVE;
+
+ gtk_paint_spinner (widget->style,
+ widget->window,
+ state_type,
+ priv->current,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ return FALSE;
+}
+
+static void
+gtk_spinner_screen_changed (GtkWidget* widget, GdkScreen* old_screen)
+{
+ GtkSpinner *spinner;
+ GdkScreen* new_screen;
+ GdkColormap* colormap;
+
+ spinner = GTK_SPINNER(widget);
+
+ new_screen = gtk_widget_get_screen (widget);
+ colormap = gdk_screen_get_rgba_colormap (new_screen);
+
+ if (!colormap)
+ {
+ colormap = gdk_screen_get_rgb_colormap (new_screen);
+ }
+
+ gtk_widget_set_colormap (widget, colormap);
+}
+
+static void
+gtk_spinner_style_set (GtkWidget *widget,
+ GtkStyle *prev_style)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER_GET_PRIVATE (widget);
+
+ gtk_widget_style_get (GTK_WIDGET (widget),
+ "num-steps", &(priv->num_steps),
+ NULL);
+
+ if (priv->current > priv->num_steps)
+ priv->current = 0;
+}
+
+static gboolean
+gtk_spinner_timeout (gpointer data)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER_GET_PRIVATE (data);
+
+ if (priv->current + 1 >= priv->num_steps)
+ {
+ priv->current = 0;
+ }
+ else
+ {
+ priv->current++;
+ }
+
+ gtk_widget_queue_draw (GTK_WIDGET (data));
+
+ return TRUE;
+}
+static void
+gtk_spinner_dispose (GObject *gobject)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER_GET_PRIVATE (gobject);
+
+ if (priv->timeout != 0)
+ {
+ g_source_remove (priv->timeout);
+ priv->timeout = 0;
+ }
+
+ G_OBJECT_CLASS (gtk_spinner_parent_class)->dispose (gobject);
+}
+
+static GType
+gtk_spinner_accessible_factory_get_accessible_type (void)
+{
+ return gtk_spinner_accessible_get_type ();
+}
+
+static AtkObject *
+gtk_spinner_accessible_new (GObject *obj)
+{
+ AtkObject *accessible;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
+
+ accessible = g_object_new (gtk_spinner_accessible_get_type (), NULL);
+ atk_object_initialize (accessible, obj);
+
+ return accessible;
+}
+
+static AtkObject*
+gtk_spinner_accessible_factory_create_accessible (GObject *obj)
+{
+ return gtk_spinner_accessible_new (obj);
+}
+
+static void
+gtk_spinner_accessible_factory_class_init (AtkObjectFactoryClass *klass)
+{
+ klass->create_accessible = gtk_spinner_accessible_factory_create_accessible;
+ klass->get_accessible_type = gtk_spinner_accessible_factory_get_accessible_type;
+}
+
+static GType
+gtk_spinner_accessible_factory_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ const GTypeInfo tinfo =
+ {
+ sizeof (AtkObjectFactoryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gtk_spinner_accessible_factory_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (AtkObjectFactory),
+ 0, /* n_preallocs */
+ NULL, NULL
+ };
+
+ type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY,
+ I_("GtkSpinnerAccessibleFactory"),
+ &tinfo, 0);
+ }
+ return type;
+}
+
+static AtkObjectClass *a11y_parent_class = NULL;
+
+static void
+gtk_spinner_accessible_initialize (AtkObject *accessible,
+ gpointer widget)
+{
+ atk_object_set_name (accessible, _("spinner"));
+ atk_object_set_description (accessible, _("provides visual status"));
+
+ a11y_parent_class->initialize (accessible, widget);
+}
+
+static void
+gtk_spinner_accessible_class_init (AtkObjectClass *klass)
+{
+ a11y_parent_class = g_type_class_peek_parent (klass);
+
+ klass->initialize = gtk_spinner_accessible_initialize;
+}
+
+static void
+gtk_spinner_accessible_image_get_size (AtkImage *image,
+ gint *width,
+ gint *height)
+{
+ GtkWidget *widget;
+
+ widget = GTK_ACCESSIBLE (image)->widget;
+ if (!widget)
+ {
+ *width = *height = 0;
+ }
+ else
+ {
+ *width = widget->allocation.width;
+ *height = widget->allocation.height;
+ }
+}
+
+static void
+gtk_spinner_accessible_image_interface_init (AtkImageIface *iface)
+{
+ iface->get_image_size = gtk_spinner_accessible_image_get_size;
+}
+
+static GType
+gtk_spinner_accessible_get_type (void)
+{
+ static GType type = 0;
+
+ /* Action interface
+ Name etc. ... */
+ if (G_UNLIKELY (type == 0))
+ {
+ const GInterfaceInfo atk_image_info = {
+ (GInterfaceInitFunc) gtk_spinner_accessible_image_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ GType type;
+ GType parent_atk_type;
+ GTypeInfo tinfo = { 0 };
+ GTypeQuery query;
+ AtkObjectFactory *factory;
+
+ if ((type = g_type_from_name ("GtkSpinnerAccessible")))
+ return type;
+
+ factory = atk_registry_get_factory (atk_get_default_registry (),
+ GTK_TYPE_IMAGE);
+ if (!factory)
+ return G_TYPE_INVALID;
+
+ parent_atk_type = atk_object_factory_get_accessible_type (factory);
+ if (!parent_atk_type)
+ return G_TYPE_INVALID;
+
+ /*
+ * Figure out the size of the class and instance
+ * we are deriving from
+ */
+ g_type_query (parent_atk_type, &query);
+
+ tinfo.class_init = (GClassInitFunc) gtk_spinner_accessible_class_init;
+ tinfo.class_size = query.class_size;
+ tinfo.instance_size = query.instance_size;
+
+ /* Register the type */
+ type = g_type_register_static (parent_atk_type,
+ "GtkSpinnerAccessible",
+ &tinfo, 0);
+
+ g_type_add_interface_static (type, ATK_TYPE_IMAGE,
+ &atk_image_info);
+ }
+
+ return type;
+}
+
+static AtkObject *
+gtk_spinner_get_accessible (GtkWidget *widget)
+{
+ static gboolean first_time = TRUE;
+
+ if (first_time)
+ {
+ AtkObjectFactory *factory;
+ AtkRegistry *registry;
+ GType derived_type;
+ GType derived_atk_type;
+
+ /*
+ * Figure out whether accessibility is enabled by looking at the
+ * type of the accessible object which would be created for
+ * the parent type of GtkSpinner.
+ */
+ derived_type = g_type_parent (GTK_TYPE_SPINNER);
+
+ registry = atk_get_default_registry ();
+ factory = atk_registry_get_factory (registry,
+ derived_type);
+ derived_atk_type = atk_object_factory_get_accessible_type (factory);
+ if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
+ atk_registry_set_factory_type (registry,
+ GTK_TYPE_SPINNER,
+ gtk_spinner_accessible_factory_get_type ());
+ first_time = FALSE;
+ }
+ return GTK_WIDGET_CLASS (gtk_spinner_parent_class)->get_accessible (widget);
+}
+
+/**
+ * gtk_spinner_new
+ *
+ * Returns a new spinner widget. Not yet started.
+ *
+ * Return value: a new #GtkSpinner
+ *
+ * Since: 2.20
+ */
+GtkWidget *
+gtk_spinner_new (void)
+{
+ return g_object_new (GTK_TYPE_SPINNER, NULL);
+}
+
+/**
+ * gtk_spinner_start
+ *
+ * Starts the animation on the #GtkSpinner
+ *
+ * Since: 2.20
+ */
+void
+gtk_spinner_start (GtkSpinner *spinner)
+{
+ GtkSpinnerPrivate *priv;
+
+ g_return_if_fail (GTK_IS_SPINNER (spinner));
+
+ priv = GTK_SPINNER_GET_PRIVATE (spinner);
+ if (priv->timeout != 0)
+ {
+ return;
+ }
+ priv->timeout = gdk_threads_add_timeout (1000 / priv->num_steps, gtk_spinner_timeout, spinner);
+}
+
+/**
+ * gtk_spinner_stop
+ *
+ * Stops the animation on the #GtkSpinner
+ *
+ * Since: 2.20
+ */
+void
+gtk_spinner_stop (GtkSpinner *spinner)
+{
+ GtkSpinnerPrivate *priv;
+
+ g_return_if_fail (GTK_IS_SPINNER (spinner));
+
+ priv = GTK_SPINNER_GET_PRIVATE (spinner);
+ if (priv->timeout == 0)
+ {
+ return;
+ }
+ g_source_remove (priv->timeout);
+ priv->timeout = 0;
+}
+
+#define __GTK_SPINNER_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkspinner.h b/gtk/gtkspinner.h
new file mode 100644
index 0000000000..126f589317
--- /dev/null
+++ b/gtk/gtkspinner.h
@@ -0,0 +1,65 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2007 John Stowers, Neil Jagdish Patel.
+ * Copyright (C) 2009 Bastien Nocera, David Zeuthen
+ *
+ * This library 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; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Code adapted from egg-spinner
+ * by Christian Hergert <christian.hergert@gmail.com>
+ */
+
+#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_SPINNER_H__
+#define __GTK_SPINNER_H__
+
+#include <gtk/gtkdrawingarea.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SPINNER (gtk_spinner_get_type ())
+#define GTK_SPINNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SPINNER, GtkSpinner))
+#define GTK_SPINNER_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GTK_SPINNER, GtkSpinnerClass))
+#define GTK_IS_SPINNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SPINNER))
+#define GTK_IS_SPINNER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GTK_TYPE_SPINNER))
+#define GTK_SPINNER_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SPINNER, GtkSpinnerClass))
+
+typedef struct _GtkSpinner GtkSpinner;
+typedef struct _GtkSpinnerClass GtkSpinnerClass;
+typedef struct _GtkSpinnerPrivate GtkSpinnerPrivate;
+
+struct _GtkSpinner
+{
+ GtkDrawingArea parent;
+};
+
+struct _GtkSpinnerClass
+{
+ GtkDrawingAreaClass parent_class;
+ GtkSpinnerPrivate *priv;
+};
+
+GType gtk_spinner_get_type (void) G_GNUC_CONST;
+GtkWidget *gtk_spinner_new (void);
+void gtk_spinner_start (GtkSpinner *spinner);
+void gtk_spinner_stop (GtkSpinner *spinner);
+
+G_END_DECLS
+
+#endif /* __GTK_SPINNER_H__ */
diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c
index 769fe79143..01f8ff02a6 100644
--- a/gtk/gtkstyle.c
+++ b/gtk/gtkstyle.c
@@ -313,6 +313,14 @@ static void gtk_default_draw_resize_grip (GtkStyle *style,
gint y,
gint width,
gint height);
+static void gtk_default_draw_spinner (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
static void rgb_to_hls (gdouble *r,
gdouble *g,
@@ -511,6 +519,7 @@ gtk_style_class_init (GtkStyleClass *klass)
klass->draw_expander = gtk_default_draw_expander;
klass->draw_layout = gtk_default_draw_layout;
klass->draw_resize_grip = gtk_default_draw_resize_grip;
+ klass->draw_spinner = gtk_default_draw_spinner;
g_type_class_add_private (object_class, sizeof (GtkStylePrivate));
@@ -1764,8 +1773,9 @@ gtk_style_get_style_property (GtkStyle *style,
GtkRcPropertyParser parser;
const GValue *peek_value;
- klass = g_type_class_peek (widget_type);
+ klass = g_type_class_ref (widget_type);
pspec = gtk_widget_class_find_style_property (klass, property_name);
+ g_type_class_unref (klass);
if (!pspec)
{
@@ -5598,6 +5608,80 @@ gtk_default_draw_resize_grip (GtkStyle *style,
}
}
+static void
+gtk_default_draw_spinner (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkColor *color;
+ cairo_t *cr;
+ guint num_steps;
+ gdouble dx, dy;
+ gdouble radius;
+ gdouble half;
+ gint i;
+ guint real_step;
+
+ gtk_style_get (style, GTK_TYPE_SPINNER,
+ "num-steps", &num_steps,
+ NULL);
+ real_step = step % num_steps;
+
+ /* get cairo context */
+ cr = gdk_cairo_create (window);
+
+ /* set a clip region for the expose event */
+ cairo_rectangle (cr, x, y, width, height);
+ cairo_clip (cr);
+
+ cairo_translate (cr, x, y);
+
+ /* draw clip region */
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+ color = &style->fg[state_type];
+ dx = width / 2;
+ dy = height / 2;
+ radius = MIN (width / 2, height / 2);
+ half = num_steps / 2;
+
+ for (i = 0; i < num_steps; i++)
+ {
+ gint inset = 0.7 * radius;
+
+ /* transparency is a function of time and intial value */
+ gdouble t = (gdouble) ((i + num_steps - real_step)
+ % num_steps) / num_steps;
+
+ cairo_save (cr);
+
+ cairo_set_source_rgba (cr,
+ color->red / 65535.,
+ color->green / 65535.,
+ color->blue / 65535.,
+ t);
+
+ cairo_set_line_width (cr, 2.0);
+ cairo_move_to (cr,
+ dx + (radius - inset) * cos (i * G_PI / half),
+ dy + (radius - inset) * sin (i * G_PI / half));
+ cairo_line_to (cr,
+ dx + radius * cos (i * G_PI / half),
+ dy + radius * sin (i * G_PI / half));
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+ }
+
+ /* free memory */
+ cairo_destroy (cr);
+}
+
void
_gtk_style_shade (const GdkColor *a,
GdkColor *b,
@@ -6632,6 +6716,38 @@ gtk_paint_resize_grip (GtkStyle *style,
}
/**
+ * gtk_paint_spinner:
+ * @style: a #GtkStyle
+ * @window: a #GdkWindow
+ * @state_type: a state
+ * @widget: the widget
+ * @step: the nth step, a value between 0 and GtkSpinner::num-steps
+ * @x: the x origin of the rectangle in which to draw the resize grip
+ * @y: the y origin of the rectangle in which to draw the resize grip
+ * @width: the width of the rectangle in which to draw the resize grip
+ * @height: the height of the rectangle in which to draw the resize grip
+ *
+ * Draws a spinner on @window using the given parameters.
+ */
+void
+gtk_paint_spinner (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_spinner != NULL);
+ g_return_if_fail (style->depth == gdk_drawable_get_depth (window));
+
+ GTK_STYLE_GET_CLASS (style)->draw_spinner (style, window, state_type,
+ step, x, y, width, height);
+}
+
+/**
* gtk_border_new:
*
* Allocates a new #GtkBorder structure and initializes its elements to zero.
diff --git a/gtk/gtkstyle.h b/gtk/gtkstyle.h
index a6af1779c1..3e1401bcf4 100644
--- a/gtk/gtkstyle.h
+++ b/gtk/gtkstyle.h
@@ -403,6 +403,14 @@ struct _GtkStyleClass
gint y,
gint width,
gint height);
+ void (*draw_spinner) (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
@@ -416,7 +424,6 @@ struct _GtkStyleClass
void (*_gtk_reserved9) (void);
void (*_gtk_reserved10) (void);
void (*_gtk_reserved11) (void);
- void (*_gtk_reserved12) (void);
};
struct _GtkBorder
@@ -856,7 +863,14 @@ void gtk_paint_resize_grip (GtkStyle *style,
gint y,
gint width,
gint height);
-
+void gtk_paint_spinner (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
GType gtk_border_get_type (void) G_GNUC_CONST;
GtkBorder *gtk_border_new (void) G_GNUC_MALLOC;