919 lines
28 KiB
C
919 lines
28 KiB
C
/*
|
|
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
|
|
|
|
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.1 of the License, or (at your option) any later version.
|
|
|
|
See the file COPYING for the full license text.
|
|
*/
|
|
|
|
#include "katze-throbber.h"
|
|
|
|
#include "katze-utils.h"
|
|
|
|
#include <glib/gi18n.h>
|
|
#include <math.h>
|
|
|
|
struct _KatzeThrobber
|
|
{
|
|
GtkMisc parent_instance;
|
|
|
|
GtkIconSize icon_size;
|
|
gchar* icon_name;
|
|
GdkPixbuf* pixbuf;
|
|
gchar* stock_id;
|
|
gboolean animated;
|
|
gchar* static_icon_name;
|
|
GdkPixbuf* static_pixbuf;
|
|
gchar* static_stock_id;
|
|
|
|
gint index;
|
|
gint timer_id;
|
|
gint width;
|
|
gint height;
|
|
};
|
|
|
|
G_DEFINE_TYPE (KatzeThrobber, katze_throbber, GTK_TYPE_MISC)
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
|
|
PROP_ICON_SIZE,
|
|
PROP_ICON_NAME,
|
|
PROP_PIXBUF,
|
|
PROP_ANIMATED,
|
|
PROP_STATIC_ICON_NAME,
|
|
PROP_STATIC_PIXBUF,
|
|
PROP_STATIC_STOCK_ID
|
|
};
|
|
|
|
static void
|
|
katze_throbber_dispose (GObject* object);
|
|
|
|
static void
|
|
katze_throbber_set_property (GObject* object,
|
|
guint prop_id,
|
|
const GValue* value,
|
|
GParamSpec* pspec);
|
|
|
|
static void
|
|
katze_throbber_get_property (GObject* object,
|
|
guint prop_id,
|
|
GValue* value,
|
|
GParamSpec* pspec);
|
|
|
|
static void
|
|
katze_throbber_destroy (GtkObject* object);
|
|
|
|
static void
|
|
katze_throbber_realize (GtkWidget* widget);
|
|
|
|
static void
|
|
katze_throbber_unrealize (GtkWidget* widget);
|
|
|
|
static void
|
|
katze_throbber_map (GtkWidget* widget);
|
|
|
|
static void
|
|
katze_throbber_unmap (GtkWidget* widget);
|
|
|
|
static void
|
|
katze_throbber_style_set (GtkWidget* widget,
|
|
GtkStyle* style);
|
|
|
|
static void
|
|
katze_throbber_screen_changed (GtkWidget* widget,
|
|
GdkScreen* screen_prev);
|
|
|
|
static void
|
|
katze_throbber_size_request (GtkWidget* widget,
|
|
GtkRequisition* requisition);
|
|
|
|
static gboolean
|
|
katze_throbber_expose_event (GtkWidget* widget,
|
|
GdkEventExpose* event);
|
|
|
|
static void
|
|
icon_theme_changed (KatzeThrobber* throbber);
|
|
|
|
static gboolean
|
|
katze_throbber_timeout (KatzeThrobber* throbber);
|
|
|
|
static void
|
|
katze_throbber_timeout_destroy (KatzeThrobber* throbber);
|
|
|
|
static void
|
|
katze_throbber_class_init (KatzeThrobberClass* class)
|
|
{
|
|
GObjectClass* gobject_class = G_OBJECT_CLASS (class);
|
|
gobject_class->dispose = katze_throbber_dispose;
|
|
gobject_class->set_property = katze_throbber_set_property;
|
|
gobject_class->get_property = katze_throbber_get_property;
|
|
|
|
GtkObjectClass* object_class = GTK_OBJECT_CLASS (class);
|
|
object_class->destroy = katze_throbber_destroy;
|
|
|
|
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (class);
|
|
widget_class->realize = katze_throbber_realize;
|
|
widget_class->unrealize = katze_throbber_unrealize;
|
|
widget_class->map = katze_throbber_map;
|
|
widget_class->unmap = katze_throbber_unmap;
|
|
widget_class->style_set = katze_throbber_style_set;
|
|
widget_class->screen_changed = katze_throbber_screen_changed;
|
|
widget_class->size_request = katze_throbber_size_request;
|
|
widget_class->expose_event = katze_throbber_expose_event;
|
|
|
|
GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_ICON_SIZE,
|
|
g_param_spec_int (
|
|
"icon-size",
|
|
"Icon size",
|
|
"Symbolic size to use for the animation",
|
|
0, G_MAXINT, GTK_ICON_SIZE_MENU,
|
|
flags));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_ICON_NAME,
|
|
g_param_spec_string (
|
|
"icon-name",
|
|
"Icon Name",
|
|
"The name of an icon containing animation frames",
|
|
"process-working",
|
|
flags));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_PIXBUF,
|
|
g_param_spec_object (
|
|
"pixbuf",
|
|
"Pixbuf",
|
|
"A GdkPixbuf containing animation frames",
|
|
GDK_TYPE_PIXBUF,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_ANIMATED,
|
|
g_param_spec_boolean (
|
|
"animated",
|
|
"Animated",
|
|
"Whether the throbber should be animated",
|
|
FALSE,
|
|
flags));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_STATIC_ICON_NAME,
|
|
g_param_spec_string (
|
|
"static-icon-name",
|
|
"Static Icon Name",
|
|
"The name of an icon to be used as the static image",
|
|
NULL,
|
|
flags));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_PIXBUF,
|
|
g_param_spec_object (
|
|
"static-pixbuf",
|
|
"Static Pixbuf",
|
|
"A GdkPixbuf to be used as the static image",
|
|
GDK_TYPE_PIXBUF,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_STATIC_STOCK_ID,
|
|
g_param_spec_string (
|
|
"static-stock-id",
|
|
"Static Stock ID",
|
|
"The stock ID of an icon to be used as the static image",
|
|
NULL,
|
|
flags));
|
|
}
|
|
|
|
static void
|
|
katze_throbber_init (KatzeThrobber *throbber)
|
|
{
|
|
GTK_WIDGET_SET_FLAGS (throbber, GTK_NO_WINDOW);
|
|
|
|
throbber->timer_id = -1;
|
|
}
|
|
|
|
static void
|
|
katze_throbber_dispose (GObject* object)
|
|
{
|
|
KatzeThrobber* throbber = KATZE_THROBBER (object);
|
|
|
|
if (G_UNLIKELY (throbber->timer_id >= 0))
|
|
g_source_remove (throbber->timer_id);
|
|
|
|
(*G_OBJECT_CLASS (katze_throbber_parent_class)->dispose) (object);
|
|
}
|
|
|
|
static void
|
|
katze_throbber_destroy (GtkObject* object)
|
|
{
|
|
KatzeThrobber* throbber = KATZE_THROBBER (object);
|
|
|
|
katze_assign (throbber->icon_name, NULL);
|
|
katze_object_assign (throbber->pixbuf, NULL);
|
|
katze_assign (throbber->static_icon_name, NULL);
|
|
katze_object_assign (throbber->static_pixbuf, NULL);
|
|
katze_assign (throbber->static_stock_id, NULL);
|
|
|
|
GTK_OBJECT_CLASS (katze_throbber_parent_class)->destroy (object);
|
|
}
|
|
|
|
static void
|
|
katze_throbber_set_property (GObject* object,
|
|
guint prop_id,
|
|
const GValue* value,
|
|
GParamSpec* pspec)
|
|
{
|
|
KatzeThrobber* throbber = KATZE_THROBBER (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_ICON_SIZE:
|
|
katze_throbber_set_icon_size (throbber, g_value_get_int (value));
|
|
break;
|
|
case PROP_ICON_NAME:
|
|
katze_throbber_set_icon_name (throbber, g_value_get_string (value));
|
|
break;
|
|
case PROP_PIXBUF:
|
|
katze_throbber_set_pixbuf (throbber, g_value_get_object (value));
|
|
break;
|
|
case PROP_ANIMATED:
|
|
katze_throbber_set_animated (throbber, g_value_get_boolean (value));
|
|
break;
|
|
case PROP_STATIC_ICON_NAME:
|
|
katze_throbber_set_static_icon_name (throbber, g_value_get_string (value));
|
|
break;
|
|
case PROP_STATIC_PIXBUF:
|
|
katze_throbber_set_static_pixbuf (throbber, g_value_get_object (value));
|
|
break;
|
|
case PROP_STATIC_STOCK_ID:
|
|
katze_throbber_set_static_stock_id (throbber, g_value_get_string (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
katze_throbber_get_property (GObject* object,
|
|
guint prop_id,
|
|
GValue* value,
|
|
GParamSpec* pspec)
|
|
{
|
|
KatzeThrobber* throbber = KATZE_THROBBER (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_ICON_SIZE:
|
|
g_value_set_int (value, katze_throbber_get_icon_size (throbber));
|
|
break;
|
|
case PROP_ICON_NAME:
|
|
g_value_set_string (value, katze_throbber_get_icon_name (throbber));
|
|
break;
|
|
case PROP_PIXBUF:
|
|
g_value_set_object (value, katze_throbber_get_pixbuf (throbber));
|
|
break;
|
|
case PROP_ANIMATED:
|
|
g_value_set_boolean (value, katze_throbber_get_animated (throbber));
|
|
break;
|
|
case PROP_STATIC_ICON_NAME:
|
|
g_value_set_string (value, katze_throbber_get_static_icon_name (throbber));
|
|
break;
|
|
case PROP_STATIC_PIXBUF:
|
|
g_value_set_object (value, katze_throbber_get_static_pixbuf (throbber));
|
|
break;
|
|
case PROP_STATIC_STOCK_ID:
|
|
g_value_set_string (value, katze_throbber_get_static_stock_id (throbber));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_new:
|
|
*
|
|
* Creates a new throbber widget.
|
|
*
|
|
* Return value: a new #KatzeThrobber
|
|
**/
|
|
GtkWidget*
|
|
katze_throbber_new (void)
|
|
{
|
|
KatzeThrobber* throbber = g_object_new (KATZE_TYPE_THROBBER,
|
|
NULL);
|
|
|
|
return GTK_WIDGET (throbber);
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_set_icon_size:
|
|
* @throbber: a #KatzeThrobber
|
|
* @icon_size: the new icon size
|
|
*
|
|
* Sets the desired size of the throbber image. The animation and static image
|
|
* will be displayed in this size. If a pixbuf is used for the animation every
|
|
* single frame is assumed to have this size.
|
|
**/
|
|
void
|
|
katze_throbber_set_icon_size (KatzeThrobber* throbber,
|
|
GtkIconSize icon_size)
|
|
{
|
|
GtkSettings* gtk_settings;
|
|
|
|
g_return_if_fail (KATZE_IS_THROBBER (throbber));
|
|
gtk_settings = gtk_widget_get_settings (GTK_WIDGET (throbber));
|
|
g_return_if_fail (gtk_icon_size_lookup_for_settings (gtk_settings,
|
|
icon_size,
|
|
&throbber->width,
|
|
&throbber->height));
|
|
|
|
throbber->icon_size = icon_size;
|
|
|
|
g_object_notify (G_OBJECT (throbber), "icon-size");
|
|
|
|
gtk_widget_queue_draw (GTK_WIDGET (throbber));
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_set_icon_name:
|
|
* @throbber: a #KatzeThrobber
|
|
* @icon_name: an icon name or %NULL
|
|
*
|
|
* Sets the name of an icon that should provide the animation frames.
|
|
*
|
|
* The pixbuf is automatically invalidated.
|
|
**/
|
|
void
|
|
katze_throbber_set_icon_name (KatzeThrobber* throbber,
|
|
const gchar* icon_name)
|
|
{
|
|
g_return_if_fail (KATZE_IS_THROBBER (throbber));
|
|
|
|
katze_assign (throbber->icon_name, g_strdup (icon_name));
|
|
|
|
if (icon_name)
|
|
icon_theme_changed (throbber);
|
|
|
|
g_object_notify (G_OBJECT (throbber), "icon-name");
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_set_pixbuf:
|
|
* @throbber: a #KatzeThrobber
|
|
* @pixbuf: a #GdkPixbuf or %NULL
|
|
*
|
|
* Sets the pixbuf that should provide the animation frames. Every frame
|
|
* is assumed to have the icon size of the throbber, which can be specified
|
|
* with katze_throbber_set_icon_size ().
|
|
*
|
|
* The icon name is automatically invalidated.
|
|
**/
|
|
void
|
|
katze_throbber_set_pixbuf (KatzeThrobber* throbber,
|
|
GdkPixbuf* pixbuf)
|
|
{
|
|
g_return_if_fail (KATZE_IS_THROBBER (throbber));
|
|
g_return_if_fail (!pixbuf || GDK_IS_PIXBUF (pixbuf));
|
|
|
|
katze_object_assign (throbber->pixbuf, pixbuf);
|
|
|
|
g_object_freeze_notify (G_OBJECT (throbber));
|
|
|
|
if (pixbuf)
|
|
{
|
|
g_object_ref (pixbuf);
|
|
|
|
katze_assign (throbber->icon_name, NULL);
|
|
g_object_notify (G_OBJECT (throbber), "icon-name");
|
|
}
|
|
|
|
gtk_widget_queue_draw (GTK_WIDGET (throbber));
|
|
|
|
g_object_notify (G_OBJECT (throbber), "pixbuf");
|
|
g_object_thaw_notify (G_OBJECT (throbber));
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_set_animated:
|
|
* @throbber: a #KatzeThrobber
|
|
* @animated: %TRUE to animate the throbber
|
|
*
|
|
* Sets the animation state of the throbber.
|
|
**/
|
|
void
|
|
katze_throbber_set_animated (KatzeThrobber* throbber,
|
|
gboolean animated)
|
|
{
|
|
g_return_if_fail (KATZE_IS_THROBBER (throbber));
|
|
|
|
if (G_UNLIKELY (throbber->animated == animated))
|
|
return;
|
|
|
|
throbber->animated = animated;
|
|
|
|
if (animated && (throbber->timer_id < 0))
|
|
throbber->timer_id = g_timeout_add_full (
|
|
G_PRIORITY_LOW, 50,
|
|
(GSourceFunc)katze_throbber_timeout,
|
|
throbber,
|
|
(GDestroyNotify)katze_throbber_timeout_destroy);
|
|
|
|
gtk_widget_queue_draw (GTK_WIDGET (throbber));
|
|
|
|
g_object_notify (G_OBJECT (throbber), "animated");
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_set_static_icon_name:
|
|
* @throbber: a #KatzeThrobber
|
|
* @icon_name: an icon name or %NULL
|
|
*
|
|
* Sets the name of an icon that should provide the static image.
|
|
*
|
|
* The static pixbuf and stock ID are automatically invalidated.
|
|
**/
|
|
void
|
|
katze_throbber_set_static_icon_name (KatzeThrobber* throbber,
|
|
const gchar* icon_name)
|
|
{
|
|
g_return_if_fail (KATZE_IS_THROBBER (throbber));
|
|
|
|
katze_assign (throbber->static_icon_name, g_strdup (icon_name));
|
|
|
|
g_object_freeze_notify (G_OBJECT (throbber));
|
|
|
|
if (icon_name)
|
|
{
|
|
katze_assign (throbber->static_stock_id, NULL);
|
|
|
|
icon_theme_changed (throbber);
|
|
|
|
g_object_notify (G_OBJECT (throbber), "static-pixbuf");
|
|
g_object_notify (G_OBJECT (throbber), "static-stock-id");
|
|
}
|
|
|
|
g_object_notify (G_OBJECT (throbber), "static-icon-name");
|
|
g_object_thaw_notify (G_OBJECT (throbber));
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_set_static_pixbuf:
|
|
* @throbber: a #KatzeThrobber
|
|
* @pixbuf: a #GdkPixbuf or %NULL
|
|
*
|
|
* Sets the pixbuf that should provide the static image. The pixbuf is
|
|
* assumed to have the icon size of the throbber, which can be specified
|
|
* with katze_throbber_set_icon_size ().
|
|
*
|
|
* The static icon name and stock ID are automatically invalidated.
|
|
**/
|
|
void
|
|
katze_throbber_set_static_pixbuf (KatzeThrobber* throbber,
|
|
GdkPixbuf* pixbuf)
|
|
{
|
|
g_return_if_fail (KATZE_IS_THROBBER (throbber));
|
|
g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
|
|
|
|
katze_object_assign (throbber->static_pixbuf, pixbuf);
|
|
|
|
g_object_freeze_notify (G_OBJECT (throbber));
|
|
|
|
if (pixbuf)
|
|
{
|
|
g_object_ref (pixbuf);
|
|
|
|
katze_assign (throbber->static_icon_name, NULL);
|
|
katze_assign (throbber->static_stock_id, NULL);
|
|
|
|
gtk_widget_queue_draw (GTK_WIDGET (throbber));
|
|
|
|
g_object_notify (G_OBJECT (throbber), "static-icon-name");
|
|
g_object_notify (G_OBJECT (throbber), "static-stock-id");
|
|
}
|
|
|
|
g_object_notify (G_OBJECT (throbber), "static-pixbuf");
|
|
g_object_thaw_notify (G_OBJECT (throbber));
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_set_static_stock_id:
|
|
* @throbber: a #KatzeThrobber
|
|
* @stock_id: a stock ID or %NULL
|
|
*
|
|
* Sets the stock ID of an icon that should provide the static image.
|
|
*
|
|
* The static icon name and pixbuf are automatically invalidated.
|
|
**/
|
|
void
|
|
katze_throbber_set_static_stock_id (KatzeThrobber* throbber,
|
|
const gchar* stock_id)
|
|
{
|
|
g_return_if_fail (KATZE_IS_THROBBER (throbber));
|
|
|
|
g_object_freeze_notify (G_OBJECT (throbber));
|
|
|
|
if (stock_id)
|
|
{
|
|
GtkStockItem stock_item;
|
|
g_return_if_fail (gtk_stock_lookup (stock_id, &stock_item));
|
|
|
|
g_object_notify (G_OBJECT (throbber), "static-icon-name");
|
|
g_object_notify (G_OBJECT (throbber), "static-pixbuf");
|
|
}
|
|
|
|
katze_assign (throbber->static_stock_id, g_strdup (stock_id));
|
|
|
|
if (stock_id)
|
|
icon_theme_changed (throbber);
|
|
|
|
g_object_notify (G_OBJECT (throbber), "static-stock-id");
|
|
g_object_thaw_notify (G_OBJECT (throbber));
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_get_icon_size:
|
|
* @throbber: a #KatzeThrobber
|
|
*
|
|
* Retrieves the size of the throbber.
|
|
*
|
|
* Return value: the size of the throbber
|
|
**/
|
|
GtkIconSize
|
|
katze_throbber_get_icon_size (KatzeThrobber* throbber)
|
|
{
|
|
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), GTK_ICON_SIZE_INVALID);
|
|
|
|
return throbber->icon_size;
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_get_icon_name:
|
|
* @throbber: a #KatzeThrobber
|
|
*
|
|
* Retrieves the name of the icon providing the animation frames.
|
|
*
|
|
* Return value: the name of the icon providing the animation frames, or %NULL
|
|
**/
|
|
const gchar*
|
|
katze_throbber_get_icon_name (KatzeThrobber* throbber)
|
|
{
|
|
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
|
|
|
|
return throbber->icon_name;
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_get_pixbuf:
|
|
* @throbber: a #KatzeThrobber
|
|
*
|
|
* Retrieves the #GdkPixbuf providing the animation frames if an icon name
|
|
* or pixbuf is available. The caller of this function does not own a
|
|
* reference to the returned pixbuf.
|
|
*
|
|
* Return value: the pixbuf providing the animation frames, or %NULL
|
|
**/
|
|
GdkPixbuf*
|
|
katze_throbber_get_pixbuf (KatzeThrobber* throbber)
|
|
{
|
|
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
|
|
|
|
return throbber->pixbuf;
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_get_animated:
|
|
* @throbber: a #KatzeThrobber
|
|
*
|
|
* Retrieves the status of the animation, whcih can be animated or static.
|
|
*
|
|
* Return value: %TRUE if the throbber is animated
|
|
**/
|
|
gboolean
|
|
katze_throbber_get_animated (KatzeThrobber* throbber)
|
|
{
|
|
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), FALSE);
|
|
|
|
return throbber->animated;
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_get_static_icon_name:
|
|
* @throbber: a #KatzeThrobber
|
|
*
|
|
* Retrieves the name of the icon providing the static image, if an icon name
|
|
* for the static image was specified.
|
|
*
|
|
* Return value: the name of the icon providing the static image, or %NULL
|
|
**/
|
|
const gchar*
|
|
katze_throbber_get_static_icon_name (KatzeThrobber* throbber)
|
|
{
|
|
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
|
|
|
|
return throbber->static_icon_name;
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_get_static pixbuf:
|
|
* @throbber: a #KatzeThrobber
|
|
*
|
|
* Retrieves the #GdkPixbuf providing the static image, if an icon name, a
|
|
* pixbuf or a stock ID for the static image was specified. The caller of this
|
|
* function does not own a reference to the returned pixbuf.
|
|
*
|
|
* Return value: the pixbuf providing the static image, or %NULL
|
|
**/
|
|
GdkPixbuf*
|
|
katze_throbber_get_static_pixbuf (KatzeThrobber* throbber)
|
|
{
|
|
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
|
|
|
|
return throbber->static_pixbuf;
|
|
}
|
|
|
|
/**
|
|
* katze_throbber_get_static_stock_id:
|
|
* @throbber: a #KatzeThrobber
|
|
*
|
|
* Retrieves the stock ID of the icon providing the static image, if a
|
|
* stock ID for the static image was specified.
|
|
*
|
|
* Return value: the stock ID of the icon providing the static image, or %NULL
|
|
**/
|
|
const gchar*
|
|
katze_throbber_get_static_stock_id (KatzeThrobber* throbber)
|
|
{
|
|
g_return_val_if_fail (KATZE_IS_THROBBER (throbber), NULL);
|
|
|
|
return throbber->static_stock_id;
|
|
}
|
|
|
|
static void
|
|
katze_throbber_realize (GtkWidget* widget)
|
|
{
|
|
(*GTK_WIDGET_CLASS (katze_throbber_parent_class)->realize) (widget);
|
|
|
|
icon_theme_changed (KATZE_THROBBER (widget));
|
|
}
|
|
|
|
static void
|
|
katze_throbber_unrealize (GtkWidget* widget)
|
|
{
|
|
if (GTK_WIDGET_CLASS (katze_throbber_parent_class)->unrealize)
|
|
GTK_WIDGET_CLASS (katze_throbber_parent_class)->unrealize (widget);
|
|
}
|
|
|
|
static void
|
|
pixbuf_assign_icon (GdkPixbuf** pixbuf,
|
|
const gchar* icon_name,
|
|
KatzeThrobber* throbber)
|
|
{
|
|
GdkScreen* screen;
|
|
GtkIconTheme* icon_theme;
|
|
|
|
if (*pixbuf)
|
|
g_object_unref (*pixbuf);
|
|
|
|
screen = gtk_widget_get_screen (GTK_WIDGET (throbber));
|
|
icon_theme = gtk_icon_theme_get_for_screen (screen);
|
|
*pixbuf = gtk_icon_theme_load_icon (icon_theme,
|
|
icon_name,
|
|
MAX (throbber->width, throbber->height),
|
|
(GtkIconLookupFlags) 0,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
icon_theme_changed (KatzeThrobber* throbber)
|
|
{
|
|
if (throbber->icon_name)
|
|
pixbuf_assign_icon (&throbber->pixbuf,
|
|
throbber->icon_name, throbber);
|
|
|
|
if (throbber->static_icon_name)
|
|
pixbuf_assign_icon (&throbber->static_pixbuf,
|
|
throbber->static_icon_name, throbber);
|
|
else if (throbber->static_stock_id)
|
|
katze_object_assign (throbber->static_pixbuf,
|
|
gtk_widget_render_icon (GTK_WIDGET (throbber),
|
|
throbber->static_stock_id,
|
|
throbber->icon_size,
|
|
NULL));
|
|
|
|
g_object_freeze_notify (G_OBJECT (throbber));
|
|
g_object_notify (G_OBJECT (throbber), "pixbuf");
|
|
g_object_notify (G_OBJECT (throbber), "static-pixbuf");
|
|
g_object_thaw_notify (G_OBJECT (throbber));
|
|
|
|
gtk_widget_queue_draw (GTK_WIDGET (throbber));
|
|
}
|
|
|
|
static void
|
|
katze_throbber_map (GtkWidget* widget)
|
|
{
|
|
(*GTK_WIDGET_CLASS (katze_throbber_parent_class)->map) (widget);
|
|
}
|
|
|
|
static void
|
|
katze_throbber_unmap (GtkWidget* widget)
|
|
{
|
|
if (GTK_WIDGET_CLASS (katze_throbber_parent_class)->unmap)
|
|
GTK_WIDGET_CLASS (katze_throbber_parent_class)->unmap (widget);
|
|
}
|
|
|
|
static gboolean
|
|
katze_throbber_timeout (KatzeThrobber* throbber)
|
|
{
|
|
throbber->index++;
|
|
gtk_widget_queue_draw (GTK_WIDGET (throbber));
|
|
|
|
return throbber->animated;
|
|
}
|
|
|
|
static void
|
|
katze_throbber_timeout_destroy (KatzeThrobber* throbber)
|
|
{
|
|
throbber->index = 0;
|
|
throbber->timer_id = -1;
|
|
}
|
|
|
|
static void
|
|
katze_throbber_style_set (GtkWidget* widget,
|
|
GtkStyle* prev_style)
|
|
{
|
|
if (GTK_WIDGET_CLASS (katze_throbber_parent_class)->style_set)
|
|
GTK_WIDGET_CLASS (katze_throbber_parent_class)->style_set (widget,
|
|
prev_style);
|
|
|
|
icon_theme_changed (KATZE_THROBBER (widget));
|
|
}
|
|
|
|
static void
|
|
katze_throbber_screen_changed (GtkWidget* widget,
|
|
GdkScreen* prev_screen)
|
|
{
|
|
if (GTK_WIDGET_CLASS (katze_throbber_parent_class)->screen_changed)
|
|
GTK_WIDGET_CLASS (katze_throbber_parent_class)->screen_changed (
|
|
widget,
|
|
prev_screen);
|
|
|
|
icon_theme_changed (KATZE_THROBBER (widget));
|
|
}
|
|
|
|
static void
|
|
katze_throbber_size_request (GtkWidget* widget,
|
|
GtkRequisition* requisition)
|
|
{
|
|
KatzeThrobber* throbber = KATZE_THROBBER (widget);
|
|
|
|
requisition->width = throbber->width;
|
|
requisition->height = throbber->height;
|
|
|
|
GTK_WIDGET_CLASS (katze_throbber_parent_class)->size_request (widget,
|
|
requisition);
|
|
}
|
|
|
|
static void
|
|
katze_throbber_aligned_coords (GtkWidget* widget,
|
|
gint* ax,
|
|
gint* ay)
|
|
{
|
|
gfloat xalign, yalign;
|
|
gint xpad, ypad;
|
|
|
|
gtk_misc_get_alignment (GTK_MISC (widget), &xalign, &yalign);
|
|
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
|
|
xalign = 1.0 - xalign;
|
|
gtk_misc_get_padding (GTK_MISC (widget), &xpad, &ypad);
|
|
|
|
*ax = floor (widget->allocation.x + xpad
|
|
+ ((widget->allocation.width - widget->requisition.width) * xalign));
|
|
*ay = floor (widget->allocation.y + ypad
|
|
+ ((widget->allocation.height - widget->requisition.height) * yalign));
|
|
}
|
|
|
|
static gboolean
|
|
katze_throbber_expose_event (GtkWidget* widget,
|
|
GdkEventExpose* event)
|
|
{
|
|
gint ax, ay;
|
|
KatzeThrobber* throbber = KATZE_THROBBER (widget);
|
|
|
|
if (G_UNLIKELY (!throbber->width || !throbber->height))
|
|
return TRUE;
|
|
|
|
if (G_UNLIKELY (!throbber->pixbuf && !throbber->static_pixbuf))
|
|
if (throbber->animated && !throbber->pixbuf && !throbber->icon_name)
|
|
return TRUE;
|
|
|
|
if (!throbber->animated && (throbber->static_pixbuf
|
|
|| throbber->static_icon_name || throbber->static_stock_id))
|
|
{
|
|
if (G_UNLIKELY (!throbber->static_pixbuf && throbber->static_icon_name))
|
|
{
|
|
icon_theme_changed (KATZE_THROBBER (widget));
|
|
|
|
if (!throbber->static_pixbuf)
|
|
{
|
|
g_warning (_("Named icon '%s' couldn't be loaded"),
|
|
throbber->static_icon_name);
|
|
katze_assign (throbber->static_icon_name, NULL);
|
|
g_object_notify (G_OBJECT (throbber), "static-icon-name");
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if (G_UNLIKELY (!throbber->static_pixbuf && throbber->static_stock_id))
|
|
{
|
|
icon_theme_changed (KATZE_THROBBER (widget));
|
|
|
|
if (!throbber->static_pixbuf)
|
|
{
|
|
g_warning (_("Stock icon '%s' couldn't be loaded"),
|
|
throbber->static_stock_id);
|
|
katze_assign (throbber->static_stock_id, NULL);
|
|
g_object_notify (G_OBJECT (throbber), "static-stock-id");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
katze_throbber_aligned_coords (widget, &ax, &ay);
|
|
|
|
gdk_draw_pixbuf (event->window, NULL, throbber->static_pixbuf,
|
|
0, 0, ax, ay,
|
|
throbber->width, throbber->height,
|
|
GDK_RGB_DITHER_NONE, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
if (G_UNLIKELY (throbber->icon_name && !throbber->pixbuf))
|
|
{
|
|
icon_theme_changed (KATZE_THROBBER (widget));
|
|
|
|
if (!throbber->pixbuf)
|
|
{
|
|
/* Fallback to a stock icon */
|
|
katze_assign (throbber->icon_name, g_strdup (GTK_STOCK_EXECUTE));
|
|
g_object_notify (G_OBJECT (throbber), "icon-name");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
gint cols = gdk_pixbuf_get_width (throbber->pixbuf) / throbber->width;
|
|
gint rows = gdk_pixbuf_get_height (throbber->pixbuf) / throbber->height;
|
|
|
|
if (G_UNLIKELY (cols == 1 && cols == rows))
|
|
{
|
|
katze_throbber_aligned_coords (widget, &ax, &ay);
|
|
|
|
if (throbber->animated)
|
|
gdk_draw_pixbuf (event->window, NULL, throbber->pixbuf,
|
|
0, 0, ax, ay,
|
|
throbber->width, throbber->height,
|
|
GDK_RGB_DITHER_NONE, 0, 0);
|
|
return TRUE;
|
|
}
|
|
|
|
if (G_LIKELY (cols > 0 && rows > 0))
|
|
{
|
|
gint index;
|
|
guint x, y;
|
|
|
|
katze_throbber_aligned_coords (widget, &ax, &ay);
|
|
|
|
index = throbber->index % (cols * rows);
|
|
if (G_LIKELY (throbber->timer_id >= 0))
|
|
index = MAX (index, 1);
|
|
|
|
x = (index % cols) * throbber->width;
|
|
y = (index / cols) * throbber->height;
|
|
|
|
gdk_draw_pixbuf (event->window, NULL, throbber->pixbuf,
|
|
x, y, ax, ay,
|
|
throbber->width, throbber->height,
|
|
GDK_RGB_DITHER_NONE, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
g_warning (_("Animation frames are broken"));
|
|
katze_assign (throbber->icon_name, NULL);
|
|
katze_object_assign (throbber->pixbuf, NULL);
|
|
|
|
g_object_freeze_notify (G_OBJECT (throbber));
|
|
g_object_notify (G_OBJECT (throbber), "icon-name");
|
|
g_object_notify (G_OBJECT (throbber), "pixbuf");
|
|
g_object_thaw_notify (G_OBJECT (throbber));
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|