/*
 * Copyright (c) 2004 Jean-Yves Lefort
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <gtk/gtk.h>
#include "sgtk-blinking-image.h"

/*** type definitions ********************************************************/

struct _sGtkBlinkingImagePrivate
{
  gboolean	blinking;
  gboolean	is_on;		/* is currently displaying the on pixbuf? */
  unsigned int	timeout_id;

  GdkPixbuf	*on_pixbuf;
  GdkPixbuf	*off_pixbuf;
};

/*** variable declarations ***************************************************/

static GObjectClass *parent_class = NULL;

/*** function declarations ***************************************************/

static void sgtk_blinking_image_class_init (sGtkBlinkingImageClass *class);
static void sgtk_blinking_image_init (sGtkBlinkingImage *image);
static void sgtk_blinking_image_finalize (GObject *object);

static void sgtk_blinking_image_update (sGtkBlinkingImage *image, gboolean is_on);
static gboolean sgtk_blinking_image_timeout_cb (gpointer data);

/*** implementation **********************************************************/

GType
sgtk_blinking_image_get_type (void)
{
  static GType blinking_image_type = 0;
  
  if (! blinking_image_type)
    {
      static const GTypeInfo blinking_image_info = {
	sizeof(sGtkBlinkingImageClass),
	NULL,
	NULL,
	(GClassInitFunc) sgtk_blinking_image_class_init,
	NULL,
	NULL,
	sizeof(sGtkBlinkingImage),
	0,
	(GInstanceInitFunc) sgtk_blinking_image_init,
      };
      
      blinking_image_type = g_type_register_static(GTK_TYPE_IMAGE,
						   "sGtkBlinkingImage",
						   &blinking_image_info,
						   0);
    }

  return blinking_image_type;
}

static void
sgtk_blinking_image_class_init (sGtkBlinkingImageClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS(class);

  parent_class = g_type_class_peek_parent(class);

  g_type_class_add_private(class, sizeof(sGtkBlinkingImagePrivate));

  object_class->finalize = sgtk_blinking_image_finalize;
}

static void
sgtk_blinking_image_init (sGtkBlinkingImage *image)
{
  image->priv = G_TYPE_INSTANCE_GET_PRIVATE(image, SGTK_TYPE_BLINKING_IMAGE, sGtkBlinkingImagePrivate);
  image->priv->is_on = TRUE;
}

static void
sgtk_blinking_image_finalize (GObject *object)
{
  sGtkBlinkingImage *image = SGTK_BLINKING_IMAGE(object);

  if (image->priv->blinking)
    g_source_remove(image->priv->timeout_id);
    
  if (image->priv->on_pixbuf)
    {
      g_object_unref(image->priv->on_pixbuf);
      g_object_unref(image->priv->off_pixbuf);
    }

  parent_class->finalize(object);
}

static void
sgtk_blinking_image_update (sGtkBlinkingImage *image, gboolean is_on)
{
  g_return_if_fail(SGTK_IS_BLINKING_IMAGE(image));

  gtk_image_set_from_pixbuf(GTK_IMAGE(image), is_on ? image->priv->on_pixbuf : image->priv->off_pixbuf);
  image->priv->is_on = is_on;
}

static gboolean
sgtk_blinking_image_timeout_cb (gpointer data)
{
  sGtkBlinkingImage *image = data;

  GDK_THREADS_ENTER();
  sgtk_blinking_image_update(image, ! image->priv->is_on);
  GDK_THREADS_LEAVE();

  return TRUE;			/* continue */
}

void
sgtk_blinking_image_set_from_pixbuf (sGtkBlinkingImage *image,
				     GdkPixbuf *pixbuf)
{
  int width, height;

  g_return_if_fail(SGTK_IS_BLINKING_IMAGE(image));
  g_return_if_fail(GDK_IS_PIXBUF(pixbuf));

  if (image->priv->on_pixbuf)
    {
      g_object_unref(image->priv->on_pixbuf);
      g_object_unref(image->priv->off_pixbuf);
    }

  width = gdk_pixbuf_get_width(pixbuf);
  height = gdk_pixbuf_get_height(pixbuf);

  image->priv->on_pixbuf = g_object_ref(pixbuf);
  image->priv->off_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
  gdk_pixbuf_fill(image->priv->off_pixbuf, 0); /* fill with transparency */

  sgtk_blinking_image_update(image, image->priv->is_on);
}

void
sgtk_blinking_image_set_blinking (sGtkBlinkingImage *image, gboolean blinking)
{
  g_return_if_fail(SGTK_IS_BLINKING_IMAGE(image));
  g_return_if_fail(image->priv->on_pixbuf != NULL);

  if (image->priv->blinking)
    {
      g_source_remove(image->priv->timeout_id);
      sgtk_blinking_image_update(image, TRUE);
    }

  image->priv->blinking = blinking;
  if (image->priv->blinking)
    image->priv->timeout_id = g_timeout_add(250, sgtk_blinking_image_timeout_cb, image);
}

GtkWidget *
sgtk_blinking_image_new (void)
{
  return g_object_new(SGTK_TYPE_BLINKING_IMAGE, NULL);
}
