]> spindle.queued.net Git - midori/commitdiff
Implement a throbber widget.
authorChristian Dywan <christian@twotoasts.de>
Sat, 5 Jan 2008 05:24:38 +0000 (06:24 +0100)
committerChristian Dywan <christian@twotoasts.de>
Sat, 5 Jan 2008 05:24:38 +0000 (06:24 +0100)
The throbber is used in the menubar and individual tabs.

Clean infrastructure for private G* extensions is added.

13 files changed:
.gitignore
Makefile.am
autogen.sh
configure.in
katze/Makefile.am [new file with mode: 0644]
katze/katze-throbber.c [new file with mode: 0644]
katze/katze-throbber.h [new file with mode: 0644]
katze/katze-utils.c [new file with mode: 0644]
katze/katze-utils.h [new file with mode: 0644]
katze/katze.h [new file with mode: 0644]
src/Makefile.am
src/browser.c
src/helpers.c

index 14af9aa62c1d1e1a255c4c0be31dd9aaf6b4a8b0..9f8d65224af4b30bdd542bc92a05e97e7cf83069 100644 (file)
@@ -1,11 +1,16 @@
+*.la
+*.lo
 *.o
 .deps
+.libs
 aclocal.m4
 autom4te.cache
 config.*
 configure
 depcomp
 install-sh
+libtool
+ltmain.sh
 Makefile
 Makefile.in
 missing
index cd36747b808c4a6e2ebd936e0ad3a3ee9e796c35..954188622a258c8ff93ff0076a2f9f58d0cbb41e 100644 (file)
@@ -1,6 +1,6 @@
 AUTOMAKE_OPTIONS = gnu
 
-SUBDIRS = src
+SUBDIRS = katze src
 
 desktopdir = $(datadir)/applications
 desktop_DATA = midori.desktop
index 863dee9fa798c338a3ce1aa97092c23533fd17b5..739a102c6e20f06683bf98c74575b3167fa17d45 100755 (executable)
@@ -1,5 +1,6 @@
 #!/bin/sh
 
+libtoolize --copy --force
 aclocal
 autoheader
 autoconf
index 460349661c25934f729419dd7fa5aa6889f420ed..80742357c56c48c6bbb2c27615cc238eb717d957 100644 (file)
@@ -4,6 +4,7 @@ AC_CONFIG_SRCDIR([src/main.h])
 AC_CONFIG_HEADER([config.h])
 
 AM_INIT_AUTOMAKE([AC_PACKAGE_TARNAME()], [AC_PACKAGE_VERSION()])
+AM_PROG_LIBTOOL
 
 # Checks for programs
 AC_PROG_CC
@@ -83,7 +84,8 @@ AC_DEFINE_UNQUOTED([LIBXML_VER], "$LIBXML_VER", [libXML2 version])
 
 # Here we tell the configure script which files to *create*
 AC_CONFIG_FILES([
-    Makefile     \
+    Makefile       \
+    katze/Makefile \
     src/Makefile
 ])
 AC_OUTPUT
diff --git a/katze/Makefile.am b/katze/Makefile.am
new file mode 100644 (file)
index 0000000..f0b2a9f
--- /dev/null
@@ -0,0 +1,13 @@
+INCLUDES = \
+    $(GTK_CFLAGS)
+
+noinst_LTLIBRARIES = \
+    libkatze.la
+
+libkatze_la_LIBADD = \
+    $(GTK_LIBS)
+
+libkatze_la_SOURCES = \
+    katze.h                           \
+    katze-throbber.c katze-throbber.h \
+    katze-utils.c    katze-utils.h
diff --git a/katze/katze-throbber.c b/katze/katze-throbber.c
new file mode 100644 (file)
index 0000000..fb31912
--- /dev/null
@@ -0,0 +1,878 @@
+/*
+ Copyright (C) 2007 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 <gtk/gtk.h>
+
+G_DEFINE_TYPE (KatzeThrobber, katze_throbber, GTK_TYPE_MISC)
+
+struct _KatzeThrobberPrivate
+{
+    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;
+};
+
+#define KATZE_THROBBER_GET_PRIVATE(obj) \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KATZE_TYPE_THROBBER, KatzeThrobberPrivate))
+
+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,
+                                     flags));
+
+    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,
+                                     flags));
+
+    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));
+
+    g_type_class_add_private (object_class, sizeof (KatzeThrobberPrivate));
+}
+
+static void
+katze_throbber_init (KatzeThrobber *throbber)
+{
+    GTK_WIDGET_SET_FLAGS (throbber, GTK_NO_WINDOW);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    priv->timer_id = -1;
+}
+
+static void
+katze_throbber_dispose (GObject *object)
+{
+    KatzeThrobber* throbber = KATZE_THROBBER (object);
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+
+    if (G_UNLIKELY (priv->timer_id >= 0))
+        g_source_remove (priv->timer_id);
+
+    (*G_OBJECT_CLASS (katze_throbber_parent_class)->dispose) (object);
+}
+
+static void
+katze_throbber_destroy (GtkObject *object)
+{
+    KatzeThrobber* throbber = KATZE_THROBBER (object);
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+
+    katze_assign (priv->icon_name, NULL);
+    if (priv->pixbuf)
+        katze_object_assign (priv->pixbuf, NULL);
+    katze_assign (priv->static_icon_name, NULL);
+    if (priv->static_pixbuf)
+        katze_object_assign (priv->static_pixbuf, NULL);
+    katze_assign (priv->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)
+{
+    g_return_if_fail (KATZE_IS_THROBBER (throbber));
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    g_return_if_fail (gtk_icon_size_lookup (icon_size,
+                                            &priv->width,
+                                            &priv->height));
+
+    priv->icon_size = icon_size;
+
+    g_object_notify (G_OBJECT (throbber), "icon-size");
+}
+
+/**
+ * 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));
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    katze_assign (priv->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 == NULL || GDK_IS_PIXBUF (pixbuf));
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    katze_object_assign (priv->pixbuf, pixbuf);
+
+    if (pixbuf)
+    {
+        g_object_ref (pixbuf);
+
+        katze_assign (priv->icon_name, NULL);
+    }
+
+    gtk_widget_queue_draw (GTK_WIDGET (throbber));
+
+    g_object_notify (G_OBJECT (throbber), "pixbuf");
+}
+
+/**
+ * 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));
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    if (G_UNLIKELY (priv->animated == animated))
+        return;
+
+    priv->animated = animated;
+
+    if (animated && (priv->timer_id < 0))
+        priv->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));
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    katze_assign (priv->static_icon_name, g_strdup (icon_name));
+
+    if (icon_name)
+    {
+        katze_assign (priv->static_stock_id, NULL);
+
+        icon_theme_changed (throbber);
+    }
+
+    g_object_notify (G_OBJECT (throbber), "static-icon-name");
+}
+
+/**
+ * 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));
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    katze_object_assign (priv->static_pixbuf, pixbuf);
+
+    if (pixbuf)
+    {
+        g_object_ref (pixbuf);
+
+        katze_assign (priv->static_icon_name, NULL);
+        katze_assign (priv->static_stock_id, NULL);
+    }
+
+    g_object_notify (G_OBJECT (throbber), "static-pixbuf");
+}
+
+/**
+ * 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 statc 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));
+
+    if (stock_id)
+    {
+        GtkStockItem stock_item;
+        g_return_if_fail (gtk_stock_lookup (stock_id, &stock_item));
+    }
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    katze_assign (priv->static_stock_id, g_strdup (stock_id));
+
+    if (stock_id)
+        icon_theme_changed (throbber);
+
+    g_object_notify (G_OBJECT (throbber), "static-stock-id");
+}
+
+/**
+ * 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);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    return priv->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);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    return priv->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);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    return priv->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);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    return priv->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);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    return priv->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);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    return priv->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);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+    return priv->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);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (KATZE_THROBBER (widget));
+    katze_object_assign (priv->pixbuf, NULL);
+    katze_object_assign (priv->static_pixbuf, NULL);
+}
+
+static void
+pixbuf_assign_icon (GdkPixbuf**    pixbuf,
+                    const gchar*   icon_name,
+                    KatzeThrobber* throbber)
+{
+    if (*pixbuf)
+        g_object_unref (*pixbuf);
+
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+
+    GdkScreen* screen = gtk_widget_get_screen (GTK_WIDGET (throbber));
+    GtkIconTheme* icon_theme = gtk_icon_theme_get_for_screen (screen);
+    *pixbuf = gtk_icon_theme_load_icon (icon_theme,
+                                        icon_name,
+                                        MAX (priv->width, priv->height),
+                                        (GtkIconLookupFlags) 0,
+                                        NULL);
+}
+
+static void
+icon_theme_changed (KatzeThrobber* throbber)
+{
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+
+    if (priv->icon_name)
+        pixbuf_assign_icon (&priv->pixbuf, priv->icon_name,
+                            throbber);
+
+    if (priv->static_icon_name)
+        pixbuf_assign_icon (&priv->static_pixbuf, priv->static_icon_name,
+                            throbber);
+    else if (priv->static_stock_id)
+    {
+        if (priv->static_pixbuf)
+            g_object_unref (priv->static_pixbuf);
+
+        priv->static_pixbuf = gtk_widget_render_icon (GTK_WIDGET (throbber),
+                                                      priv->static_stock_id,
+                                                      priv->icon_size,
+                                                      NULL);
+    }
+
+    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)
+{
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+
+    priv->index++;
+    gtk_widget_queue_draw (GTK_WIDGET (throbber));
+
+    return priv->animated;
+}
+
+static void
+katze_throbber_timeout_destroy (KatzeThrobber*  throbber)
+{
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (throbber);
+
+    priv->index = 0;
+    priv->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)
+{
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (KATZE_THROBBER (widget));
+
+    requisition->width = priv->width;
+    requisition->height = priv->height;
+
+    GTK_WIDGET_CLASS (katze_throbber_parent_class)->size_request (widget,
+                                                                  requisition);
+}
+
+static gboolean
+katze_throbber_expose_event (GtkWidget*      widget,
+                             GdkEventExpose* event)
+{
+    KatzeThrobberPrivate* priv = KATZE_THROBBER_GET_PRIVATE (KATZE_THROBBER (widget));
+
+    if (G_UNLIKELY (!priv->width || !priv->height))
+        return TRUE;
+
+    if (G_UNLIKELY (!priv->pixbuf && !priv->static_pixbuf))
+        if (priv->animated && !priv->pixbuf && !priv->icon_name)
+            return TRUE;
+
+    if (!priv->animated &&
+        (priv->static_pixbuf || priv->static_icon_name || priv->static_stock_id))
+    {
+        if (G_UNLIKELY (!priv->static_pixbuf && priv->static_icon_name))
+        {
+            icon_theme_changed (KATZE_THROBBER (widget));
+
+            if (!priv->static_pixbuf)
+            {
+                g_warning ("Named icon '%s' couldn't be loaded",
+                           priv->static_icon_name);
+                katze_assign (priv->static_icon_name, NULL);
+                return TRUE;
+            }
+        }
+        else if (G_UNLIKELY (!priv->static_pixbuf && priv->static_stock_id))
+        {
+            icon_theme_changed (KATZE_THROBBER (widget));
+
+            if (!priv->static_pixbuf)
+            {
+                g_warning ("Stock icon '%s' couldn't be loaded",
+                           priv->static_stock_id);
+                katze_assign (priv->static_stock_id, NULL);
+                return TRUE;
+            }
+        }
+
+        gdk_draw_pixbuf (event->window, NULL, priv->static_pixbuf,
+                         0, 0,
+                         widget->allocation.x,
+                         widget->allocation.y,
+                         priv->width, priv->height,
+                         GDK_RGB_DITHER_NONE, 0, 0);
+    }
+    else
+    {
+        if (G_UNLIKELY (priv->icon_name && !priv->pixbuf))
+        {
+            icon_theme_changed (KATZE_THROBBER (widget));
+
+            if (!priv->pixbuf)
+            {
+                g_warning ("Icon '%s' couldn't be loaded", priv->icon_name);
+                katze_assign (priv->icon_name, NULL);
+                return TRUE;
+            }
+        }
+
+        if (G_UNLIKELY (!priv->pixbuf))
+            return TRUE;
+
+        gint cols = gdk_pixbuf_get_width (priv->pixbuf) / priv->width;
+        gint rows = gdk_pixbuf_get_height (priv->pixbuf) / priv->height;
+
+        if (G_LIKELY (cols > 0 && rows > 0))
+        {
+            gint index = priv->index % (cols * rows);
+
+            if (G_LIKELY (priv->timer_id >= 0))
+                index = MAX (index, 1);
+
+            guint x = (index % cols) * priv->width;
+            guint y = (index / cols) * priv->height;
+
+            gdk_draw_pixbuf (event->window, NULL, priv->pixbuf,
+                             x, y,
+                             widget->allocation.x,
+                             widget->allocation.y,
+                             priv->width, priv->height,
+                             GDK_RGB_DITHER_NONE, 0, 0);
+        }
+        else
+        {
+            g_warning ("Animation frames are broken");
+            katze_assign (priv->icon_name, NULL);
+            katze_object_assign (priv->pixbuf, NULL);
+        }
+    }
+
+    return TRUE;
+}
diff --git a/katze/katze-throbber.h b/katze/katze-throbber.h
new file mode 100644 (file)
index 0000000..ebd5102
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2007 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.
+*/
+
+#ifndef __KATZE_THROBBER_H__
+#define __KATZE_THROBBER_H__
+
+#include <gdk/gdk.h>
+#include <gtk/gtkmisc.h>
+
+#include "katze-utils.h"
+
+G_BEGIN_DECLS
+
+#define KATZE_TYPE_THROBBER \
+    (katze_throbber_get_type ())
+#define KATZE_THROBBER(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_THROBBER, KatzeThrobber))
+#define KATZE_THROBBER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_THROBBER, KatzeThrobberClass))
+#define KATZE_IS_THROBBER(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_THROBBER))
+#define KATZE_IS_THROBBER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_THROBBER))
+#define KATZE_THROBBER_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_THROBBER, KatzeThrobberClass))
+
+typedef struct _KatzeThrobber                KatzeThrobber;
+typedef struct _KatzeThrobberPrivate         KatzeThrobberPrivate;
+typedef struct _KatzeThrobberClass           KatzeThrobberClass;
+
+struct _KatzeThrobber
+{
+    KatzeThrobberPrivate* priv;
+    GtkWidget parent_object;
+
+    /* Padding for future expansion */
+    void (*_katze_reserved1) (void);
+    void (*_katze_reserved2) (void);
+    void (*_katze_reserved3) (void);
+    void (*_katze_reserved4) (void);
+};
+
+struct _KatzeThrobberClass
+{
+    GtkMiscClass parent_class;
+
+    /* Padding for future expansion */
+    void (*_katze_reserved1) (void);
+    void (*_katze_reserved2) (void);
+    void (*_katze_reserved3) (void);
+    void (*_katze_reserved4) (void);
+};
+
+GType
+katze_throbber_get_type             (void) G_GNUC_CONST;
+
+GtkWidget*
+katze_throbber_new                  (void);
+
+void
+katze_throbber_set_icon_size        (KatzeThrobber*   throbber,
+                                     GtkIconSize      icon_size);
+
+void
+katze_throbber_set_icon_name        (KatzeThrobber*   throbber,
+                                     const gchar*     icon_size);
+
+void
+katze_throbber_set_pixbuf           (KatzeThrobber*   throbber,
+                                     GdkPixbuf*       pixbuf);
+
+void
+katze_throbber_set_animated         (KatzeThrobber*   throbber,
+                                     gboolean         animated);
+
+void
+katze_throbber_set_static_icon_name (KatzeThrobber*   throbber,
+                                     const gchar*     icon_name);
+
+void
+katze_throbber_set_static_pixbuf    (KatzeThrobber*   throbber,
+                                     GdkPixbuf*       pixbuf);
+
+void
+katze_throbber_set_static_stock_id  (KatzeThrobber*   throbber,
+                                     const gchar*     stock_id);
+
+GtkIconSize
+katze_throbber_get_icon_size        (KatzeThrobber*   throbber);
+
+const gchar*
+katze_throbber_get_icon_name        (KatzeThrobber*   throbber);
+
+GdkPixbuf*
+katze_throbber_get_pixbuf           (KatzeThrobber*   throbber);
+
+gboolean
+katze_throbber_get_animated         (KatzeThrobber*   throbber);
+
+const gchar*
+katze_throbber_get_static_icon_name (KatzeThrobber    *throbber);
+
+GdkPixbuf*
+katze_throbber_get_static_pixbuf    (KatzeThrobber*   throbber);
+
+const gchar*
+katze_throbber_get_static_stock_id  (KatzeThrobber*   throbber);
+
+G_END_DECLS
+
+#endif /* __KATZE_THROBBER_H__ */
diff --git a/katze/katze-utils.c b/katze/katze-utils.c
new file mode 100644 (file)
index 0000000..620a5d0
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ Copyright (C) 2007 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-utils.h"
diff --git a/katze/katze-utils.h b/katze/katze-utils.h
new file mode 100644 (file)
index 0000000..45dda89
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2007 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.
+*/
+
+#ifndef __KATZE_UTILS_H__
+#define __KATZE_UTILS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/**
+ * katze_assign:
+ * @lvalue: a pointer
+ * @rvalue: the new value
+ *
+ * Frees @lvalue if needed and assigns it the value of @rvalue.
+ **/
+#define katze_assign(lvalue, rvalue) \
+    if (1) \
+    { \
+        g_free (lvalue); \
+        lvalue = rvalue; \
+    }
+
+/**
+ * katze_object_assign:
+ * @lvalue: a gobject
+ * @rvalue: the new value
+ *
+ * Unrefs @lvalue if needed and assigns it the value of @rvalue.
+ **/
+#define katze_object_assign(lvalue, rvalue) \
+    if (1) \
+    { \
+        if (lvalue) \
+            g_object_unref (lvalue); \
+        lvalue = rvalue; \
+    }
+
+G_END_DECLS
+
+#endif /* __KATZE_UTILS_H__ */
diff --git a/katze/katze.h b/katze/katze.h
new file mode 100644 (file)
index 0000000..f401be3
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ Copyright (C) 2007 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.
+*/
+
+#ifndef __KATZE__
+#define __KATZE__
+
+#include "katze-throbber.h"
+#include "katze-utils.h"
+
+#endif /* __KATZE_THROBBER_H__ */
index c8db7753e60a9073e4e927c758f3b23068e28276..6246932aac191285461a038afe70459ec54acd7c 100644 (file)
@@ -1,17 +1,31 @@
-INCLUDES = $(GTK_CFLAGS) $(WEBKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBSEXY_CFLAGS)
-LDADD = $(GTK_LIBS) $(WEBKIT_LIBS) $(LIBXML_LIBS) $(LIBSEXY_LIBS)
+INCLUDES = \
+    $(GTK_CFLAGS)     \
+    $(WEBKIT_CFLAGS)  \
+    $(LIBXML_CFLAGS)  \
+    $(LIBSEXY_CFLAGS) \
+    -I../katze
 
-bin_PROGRAMS = midori
-midori_SOURCES = main.c      main.h      \
-                 browser.c   browser.h   \
-                 prefs.c     prefs.h     \
-                 webSearch.c webSearch.h \
-                 helpers.c   helpers.h   \
-                 webView.c   webView.h   \
-                 sokoke.c    sokoke.h    \
-                 conf.c      conf.h      \
-                 search.c    search.h    \
-                 xbel.c      xbel.h      \
-                 global.h                \
-                 ui.h                    \
-                 debug.h
+LDADD = \
+    $(GTK_LIBS)          \
+    $(WEBKIT_LIBS)       \
+    $(LIBXML_LIBS)       \
+    $(LIBSEXY_LIBS)      \
+    ../katze/libkatze.la
+
+bin_PROGRAMS = \
+    midori
+
+midori_SOURCES = \
+    main.c      main.h      \
+    browser.c   browser.h   \
+    prefs.c     prefs.h     \
+    webSearch.c webSearch.h \
+    helpers.c   helpers.h   \
+    webView.c   webView.h   \
+    sokoke.c    sokoke.h    \
+    conf.c      conf.h      \
+    search.c    search.h    \
+    xbel.c      xbel.h      \
+    global.h                \
+    ui.h                    \
+    debug.h
index f98d401673c272795bb0c709af2c61b7dbafc1d1..8dac19a547749240b0a5f3a7eacef4938ac24646 100644 (file)
@@ -18,6 +18,7 @@
 #include "webView.h"
 #include "webSearch.h"
 #include "xbel.h"
+#include "../katze/katze.h"
 
 #include <gdk/gdkkeysyms.h>
 #include <string.h>
@@ -1190,7 +1191,7 @@ CBrowser* browser_new(CBrowser* oldBrowser)
     browser->menubar = gtk_ui_manager_get_widget(ui_manager, "/menubar");
     GtkWidget* menuitem = gtk_menu_item_new();
     gtk_widget_show(menuitem);
-    browser->throbber = gtk_image_new_from_stock(GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU);
+    browser->throbber = katze_throbber_new();
     gtk_widget_show(browser->throbber);
     gtk_container_add(GTK_CONTAINER(menuitem), browser->throbber);
     gtk_widget_set_sensitive(menuitem, FALSE);
@@ -1561,7 +1562,9 @@ CBrowser* browser_new(CBrowser* oldBrowser)
      , G_CALLBACK(on_notebook_tab_mouse_up), browser);
     GtkWidget* hbox = gtk_hbox_new(FALSE, 1);
     gtk_container_add(GTK_CONTAINER(eventbox), GTK_WIDGET(hbox));
-    browser->webView_icon = gtk_image_new_from_stock(GTK_STOCK_FILE, GTK_ICON_SIZE_MENU);
+    browser->webView_icon = katze_throbber_new();
+    katze_throbber_set_static_stock_id(KATZE_THROBBER(browser->webView_icon)
+     , GTK_STOCK_FILE);
     gtk_box_pack_start(GTK_BOX(hbox), browser->webView_icon, FALSE, FALSE, 0);
     browser->webView_name = gtk_label_new(xbel_item_get_title(browser->sessionItem));
     gtk_misc_set_alignment(GTK_MISC(browser->webView_name), 0.0, 0.5);
index 2981931c0b68ef4d77279c2a222b17adc92d3e14..74ed68e6dc989dec016f3802f39e5307d202e446 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "search.h"
 #include "sokoke.h"
+#include "../katze/katze.h"
 
 #include <string.h>
 #include <webkit.h>
@@ -231,14 +232,11 @@ void update_favicon(CBrowser* browser)
             // TODO: Retrieve mime type and load icon; don't forget ftp listings
         }
         else
-            gtk_image_set_from_stock(GTK_IMAGE(browser->webView_icon)
-             , GTK_STOCK_FILE, GTK_ICON_SIZE_MENU);
-    }
-    else
-    {
-        gtk_image_set_from_stock(GTK_IMAGE(browser->webView_icon)
-         , GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU);
+            katze_throbber_set_static_stock_id(KATZE_THROBBER(browser->webView_icon)
+             , GTK_STOCK_FILE);
     }
+    katze_throbber_set_animated(KATZE_THROBBER(browser->webView_icon)
+     , browser->loadedPercent != -1);
 }
 
 void update_security(CBrowser* browser)
@@ -382,6 +380,8 @@ void update_gui_state(CBrowser* browser)
         g_object_set(action, "tooltip", "Stop loading the current page", NULL);
         gtk_widget_show(browser->progress);
     }
+    katze_throbber_set_animated(KATZE_THROBBER(browser->throbber)
+     , browser->loadedPercent != -1);
 
     gtk_image_set_from_stock(GTK_IMAGE(browser->location_icon), GTK_STOCK_FILE
      , GTK_ICON_SIZE_MENU);