Commit d21700f5 authored by Bastien Nocera's avatar Bastien Nocera
Browse files

Bug 319607 – Add a throbber (activity widget) to GTK+

Add GtkSpinner activity throbber, as well as a cell renderer.
parent df53e6ad
......@@ -37,6 +37,7 @@ demos = \
rotated_text.c \
search_entry.c \
sizegroup.c \
spinner.c \
stock_browser.c \
textview.c \
textscroll.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;
......
/* 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;
}
......@@ -3584,6 +3584,24 @@ GTK_SPIN_BUTTON_GET_CLASS
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>
......@@ -5106,6 +5124,23 @@ GtkCellRendererSpinPrivate
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>
......@@ -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
......
......@@ -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 \
......
......@@ -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>
......
......@@ -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
......
/* 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,