C++程序  |  540行  |  13.09 KB

/* 
INTEL CONFIDENTIAL
Copyright 2009 Intel Corporation All Rights Reserved. 
The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material contains trade secrets and proprietary and confidential information of Intel or its suppliers and licensors. The Material is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intel’s prior express written permission.

No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing.
*/

/**
* SECTION:mixdisplay
* @short_description: Lightweight base class for the MIX media display
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "mixdisplay.h"
#include <gobject/gvaluecollector.h>

#define DEBUG_REFCOUNT

static void mix_display_class_init (gpointer g_class, gpointer class_data);
static void mix_display_init (GTypeInstance * instance, gpointer klass);

static void mix_value_display_init (GValue * value);
static void mix_value_display_free (GValue * value);
static void mix_value_display_copy (const GValue * src_value,
				    GValue * dest_value);
static gpointer mix_value_display_peek_pointer (const GValue * value);
static gchar *mix_value_display_collect (GValue * value,
					 guint n_collect_values,
					 GTypeCValue * collect_values,
					 guint collect_flags);
static gchar *mix_value_display_lcopy (const GValue * value,
				       guint n_collect_values,
				       GTypeCValue * collect_values,
				       guint collect_flags);

static void mix_display_finalize (MixDisplay * obj);
static gboolean mix_display_copy_default (MixDisplay * target,
					  const MixDisplay * src);
static MixDisplay *mix_display_dup_default (const MixDisplay * obj);
static gboolean mix_display_equal_default (MixDisplay * first,
					   MixDisplay * second);

GType
mix_display_get_type (void)
{
  static GType _mix_display_type = 0;

  if (G_UNLIKELY (_mix_display_type == 0))
    {

      GTypeValueTable value_table = {
	mix_value_display_init,
	mix_value_display_free,
	mix_value_display_copy,
	mix_value_display_peek_pointer,
	"p",
	mix_value_display_collect,
	"p",
	mix_value_display_lcopy
      };

      GTypeInfo info = {
	sizeof (MixDisplayClass),
	NULL,
	NULL,
	mix_display_class_init,
	NULL,
	NULL,
	sizeof (MixDisplay),
	0,
	(GInstanceInitFunc) mix_display_init,
	NULL
      };

      static const GTypeFundamentalInfo fundamental_info = {
	(G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE |
	 G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE)
      };

      info.value_table = &value_table;

      _mix_display_type = g_type_fundamental_next ();
      g_type_register_fundamental (_mix_display_type, "MixDisplay",
				   &info, &fundamental_info,
				   G_TYPE_FLAG_ABSTRACT);

    }

  return _mix_display_type;
}

static void
mix_display_class_init (gpointer g_class, gpointer class_data)
{
  MixDisplayClass *klass = MIX_DISPLAY_CLASS (g_class);

  klass->dup = mix_display_dup_default;
  klass->copy = mix_display_copy_default;
  klass->finalize = mix_display_finalize;
  klass->equal = mix_display_equal_default;
}

static void
mix_display_init (GTypeInstance * instance, gpointer klass)
{
  MixDisplay *obj = MIX_DISPLAY_CAST (instance);

  obj->refcount = 1;
}

gboolean
mix_display_copy (MixDisplay * target, const MixDisplay * src)
{
  /* Use the target object class. Because it knows what it is looking for. */
  MixDisplayClass *klass = MIX_DISPLAY_GET_CLASS (target);
  if (klass->copy)
    {
      return klass->copy (target, src);
    }
  else
    {
      return mix_display_copy_default (target, src);
    }
}

/**
* mix_display_copy_default:
* @target:
* @src:
* 
* The default copy method of this object. Perhap copy at this level.
* Assign this to the copy vmethod.
*/
static gboolean
mix_display_copy_default (MixDisplay * target, const MixDisplay * src)
{
  if (MIX_IS_DISPLAY (target) && MIX_IS_DISPLAY (src))
    {
      // TODO perform deep copy.
      return TRUE;
    }
  return FALSE;
}

static void
mix_display_finalize (MixDisplay * obj)
{
  /* do nothing */
}

MixDisplay *
mix_display_dup (const MixDisplay * obj)
{
  MixDisplayClass *klass = MIX_DISPLAY_GET_CLASS (obj);

  if (klass->dup)
    {
      return klass->dup (obj);
    }
  else if (MIX_IS_DISPLAY (obj))
    {
      return mix_display_dup_default (obj);
    }
  return NULL;
}

static MixDisplay *
mix_display_dup_default (const MixDisplay * obj)
{
  MixDisplay *ret = mix_display_new ();
  if (mix_display_copy (ret, obj))
    {
      return ret;
    }

  return NULL;
}

MixDisplay *
mix_display_new (GType type)
{
  MixDisplay *obj;

  /* we don't support dynamic types because they really aren't useful,
   * and could cause refcount problems */
  obj = (MixDisplay *) g_type_create_instance (type);

  return obj;
}

MixDisplay *
mix_display_ref (MixDisplay * obj)
{
  g_return_val_if_fail (MIX_IS_DISPLAY (obj), NULL);

  g_atomic_int_inc (&obj->refcount);

  return obj;
}

static void
mix_display_free (MixDisplay * obj)
{
  MixDisplayClass *klass = NULL;

  klass = MIX_DISPLAY_GET_CLASS (obj);
  klass->finalize (obj);

  /* Should we support recycling the object? */
  /* If so, refcount handling is slightly different. */
  /* i.e. If the refcount is still 0 we can really free the object, else the finalize method recycled the object -- but to where? */

  if (g_atomic_int_get (&obj->refcount) == 0)
    {

      g_type_free_instance ((GTypeInstance *) obj);
    }
}

void
mix_display_unref (MixDisplay * obj)
{
  g_return_if_fail (obj != NULL);
  g_return_if_fail (obj->refcount > 0);

  if (G_UNLIKELY (g_atomic_int_dec_and_test (&obj->refcount)))
    {
      mix_display_free (obj);
    }
}

static void
mix_value_display_init (GValue * value)
{
  value->data[0].v_pointer = NULL;
}

static void
mix_value_display_free (GValue * value)
{
  if (value->data[0].v_pointer)
    {
      mix_display_unref (MIX_DISPLAY_CAST (value->data[0].v_pointer));
    }
}

static void
mix_value_display_copy (const GValue * src_value, GValue * dest_value)
{
  if (src_value->data[0].v_pointer)
    {
      dest_value->data[0].v_pointer =
	mix_display_ref (MIX_DISPLAY_CAST (src_value->data[0].v_pointer));
    }
  else
    {
      dest_value->data[0].v_pointer = NULL;
    }
}

static gpointer
mix_value_display_peek_pointer (const GValue * value)
{
  return value->data[0].v_pointer;
}

static gchar *
mix_value_display_collect (GValue * value, guint n_collect_values,
			   GTypeCValue * collect_values, guint collect_flags)
{
  mix_value_set_display (value, collect_values[0].v_pointer);

  return NULL;
}

static gchar *
mix_value_display_lcopy (const GValue * value,
			 guint n_collect_values,
			 GTypeCValue * collect_values, guint collect_flags)
{
  gpointer *obj_p = collect_values[0].v_pointer;

  if (!obj_p)
    {
      return g_strdup_printf ("value location for '%s' passed as NULL",
			      G_VALUE_TYPE_NAME (value));
    }

  if (!value->data[0].v_pointer)
    *obj_p = NULL;
  else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
    *obj_p = value->data[0].v_pointer;
  else
    *obj_p = mix_display_ref (value->data[0].v_pointer);

  return NULL;
}

/**
* mix_value_set_display:
* @value:       a valid #GValue of %MIX_TYPE_DISPLAY derived type
* @obj: object value to set
*
* Set the contents of a %MIX_TYPE_DISPLAY derived #GValue to
* @obj.
* The caller retains ownership of the reference.
*/
void
mix_value_set_display (GValue * value, MixDisplay * obj)
{
  gpointer *pointer_p;

  g_return_if_fail (MIX_VALUE_HOLDS_DISPLAY (value));
  g_return_if_fail (obj == NULL || MIX_IS_DISPLAY (obj));

  pointer_p = &value->data[0].v_pointer;
  mix_display_replace ((MixDisplay **) pointer_p, obj);
}

/**
* mix_value_take_display:
* @value: a valid #GValue of #MIX_TYPE_DISPLAY derived type
* @obj: object value to take
*
* Set the contents of a #MIX_TYPE_DISPLAY derived #GValue to
* @obj.
* Takes over the ownership of the caller's reference to @obj;
* the caller doesn't have to unref it any more.
*/
void
mix_value_take_display (GValue * value, MixDisplay * obj)
{
  gpointer *pointer_p;

  g_return_if_fail (MIX_VALUE_HOLDS_DISPLAY (value));
  g_return_if_fail (obj == NULL || MIX_IS_DISPLAY (obj));

  pointer_p = &value->data[0].v_pointer;
  mix_display_replace ((MixDisplay **) pointer_p, obj);
  if (obj)
    mix_display_unref (obj);
}

/**
* mix_value_get_display:
* @value: a valid #GValue of #MIX_TYPE_DISPLAY derived type
* @returns:object contents of @value 
*
* refcount of the MixDisplay is not increased.
*/
MixDisplay *
mix_value_get_display (const GValue * value)
{
  g_return_val_if_fail (MIX_VALUE_HOLDS_DISPLAY (value), NULL);

  return value->data[0].v_pointer;
}

/**
* mix_value_dup_display:
* @value:   a valid #GValue of %MIX_TYPE_DISPLAY derived type
* @returns: object contents of @value
*
* refcount of MixDisplay is increased.
*/
MixDisplay *
mix_value_dup_display (const GValue * value)
{
  g_return_val_if_fail (MIX_VALUE_HOLDS_DISPLAY (value), NULL);

  return mix_display_ref (value->data[0].v_pointer);
}


static void
param_display_init (GParamSpec * pspec)
{
  /* GParamSpecDisplay *ospec = G_PARAM_SPEC_DISPLAY (pspec); */
}

static void
param_display_set_default (GParamSpec * pspec, GValue * value)
{
  value->data[0].v_pointer = NULL;
}

static gboolean
param_display_validate (GParamSpec * pspec, GValue * value)
{
  gboolean validated = FALSE;
  MixParamSpecDisplay *ospec = MIX_PARAM_SPEC_DISPLAY (pspec);
  MixDisplay *obj = value->data[0].v_pointer;

  if (obj && !g_value_type_compatible (G_OBJECT_TYPE (obj), G_PARAM_SPEC_VALUE_TYPE (ospec)))
    {
      mix_display_unref (obj);
      value->data[0].v_pointer = NULL;
      validated = TRUE;
    }

  return validated;
}

static gint
param_display_values_cmp (GParamSpec * pspec,
			  const GValue * value1, const GValue * value2)
{
  guint8 *p1 = value1->data[0].v_pointer;
  guint8 *p2 = value2->data[0].v_pointer;


  return p1 < p2 ? -1 : p1 > p2;
}

GType
mix_param_spec_display_get_type (void)
{
  static GType type;

  if (G_UNLIKELY (type) == 0)
    {
      static const GParamSpecTypeInfo pspec_info = {
	sizeof (MixParamSpecDisplay),	/* instance_size */
	16,			/* n_preallocs */
	param_display_init,	/* instance_init */
	G_TYPE_OBJECT,		/* value_type */
	NULL,			/* finalize */
	param_display_set_default,	/* value_set_default */
	param_display_validate,	/* value_validate */
	param_display_values_cmp,	/* values_cmp */
      };
      /* FIXME 0.11: Should really be MixParamSpecDisplay */
      type = g_param_type_register_static ("GParamSpecDisplay", &pspec_info);
    }

  return type;
}

/**
* mix_param_spec_display:
* @name: the canonical name of the property
* @nick: the nickname of the property
* @blurb: a short description of the property
* @object_type: the #MixDisplayType for the property
* @flags: a combination of #GParamFlags
* @returns: a newly allocated #GParamSpec instance
*
* Creates a new #GParamSpec instance that hold #MixDisplay references.
*
*/
GParamSpec *
mix_param_spec_display (const char *name, const char *nick,
			const char *blurb, GType object_type,
			GParamFlags flags)
{
  MixParamSpecDisplay *ospec;

  g_return_val_if_fail (g_type_is_a (object_type, MIX_TYPE_DISPLAY), NULL);

  ospec = g_param_spec_internal (MIX_TYPE_PARAM_DISPLAY,
				 name, nick, blurb, flags);
  G_PARAM_SPEC (ospec)->value_type = object_type;

  return G_PARAM_SPEC (ospec);
}

/**
* mix_display_replace:
* @olddata: pointer to a pointer to a object to be replaced
* @newdata: pointer to new object
*
* Modifies a pointer to point to a new object.  The modification
* is done atomically, and the reference counts are updated correctly.
* Either @newdata and the value pointed to by @olddata may be NULL.
*/
void
mix_display_replace (MixDisplay ** olddata, MixDisplay * newdata)
{
  MixDisplay *olddata_val;

  g_return_if_fail (olddata != NULL);

  olddata_val = g_atomic_pointer_get ((gpointer *) olddata);

  if (olddata_val == newdata)
    return;

  if (newdata)
    mix_display_ref (newdata);

  while (!g_atomic_pointer_compare_and_exchange
	 ((gpointer *) olddata, olddata_val, newdata))
    {
      olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
    }

  if (olddata_val)
    mix_display_unref (olddata_val);

}

gboolean
mix_display_equal (MixDisplay * first, MixDisplay * second)
{
  if (MIX_IS_DISPLAY (first))
    {
      MixDisplayClass *klass = MIX_DISPLAY_GET_CLASS (first);

      if (klass->equal)
	{
	  return klass->equal (first, second);
	}
      else
	{
	  return mix_display_equal_default (first, second);
	}
    }
  else
    return FALSE;
}

static gboolean
mix_display_equal_default (MixDisplay * first, MixDisplay * second)
{
  if (MIX_IS_DISPLAY (first) && MIX_IS_DISPLAY (second))
    {
      gboolean ret = TRUE;

      // Do data comparison here.

      return ret;
    }
  else
    return FALSE;
}