Home | History | Annotate | Download | only in src
      1 /*
      2 INTEL CONFIDENTIAL
      3 Copyright 2009 Intel Corporation All Rights Reserved.
      4 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 Intels prior express written permission.
      5 
      6 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.
      7 */
      8 
      9 /**
     10 * SECTION:mixdisplay
     11 * @short_description: Lightweight base class for the MIX media display
     12 *
     13 */
     14 #ifdef HAVE_CONFIG_H
     15 #include "config.h"
     16 #endif
     17 
     18 #include "mixdisplay.h"
     19 #include <gobject/gvaluecollector.h>
     20 
     21 #define DEBUG_REFCOUNT
     22 
     23 static void mix_display_class_init (gpointer g_class, gpointer class_data);
     24 static void mix_display_init (GTypeInstance * instance, gpointer klass);
     25 
     26 static void mix_value_display_init (GValue * value);
     27 static void mix_value_display_free (GValue * value);
     28 static void mix_value_display_copy (const GValue * src_value,
     29 				    GValue * dest_value);
     30 static gpointer mix_value_display_peek_pointer (const GValue * value);
     31 static gchar *mix_value_display_collect (GValue * value,
     32 					 guint n_collect_values,
     33 					 GTypeCValue * collect_values,
     34 					 guint collect_flags);
     35 static gchar *mix_value_display_lcopy (const GValue * value,
     36 				       guint n_collect_values,
     37 				       GTypeCValue * collect_values,
     38 				       guint collect_flags);
     39 
     40 static void mix_display_finalize (MixDisplay * obj);
     41 static gboolean mix_display_copy_default (MixDisplay * target,
     42 					  const MixDisplay * src);
     43 static MixDisplay *mix_display_dup_default (const MixDisplay * obj);
     44 static gboolean mix_display_equal_default (MixDisplay * first,
     45 					   MixDisplay * second);
     46 
     47 GType
     48 mix_display_get_type (void)
     49 {
     50   static GType _mix_display_type = 0;
     51 
     52   if (G_UNLIKELY (_mix_display_type == 0))
     53     {
     54 
     55       GTypeValueTable value_table = {
     56 	mix_value_display_init,
     57 	mix_value_display_free,
     58 	mix_value_display_copy,
     59 	mix_value_display_peek_pointer,
     60 	"p",
     61 	mix_value_display_collect,
     62 	"p",
     63 	mix_value_display_lcopy
     64       };
     65 
     66       GTypeInfo info = {
     67 	sizeof (MixDisplayClass),
     68 	NULL,
     69 	NULL,
     70 	mix_display_class_init,
     71 	NULL,
     72 	NULL,
     73 	sizeof (MixDisplay),
     74 	0,
     75 	(GInstanceInitFunc) mix_display_init,
     76 	NULL
     77       };
     78 
     79       static const GTypeFundamentalInfo fundamental_info = {
     80 	(G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE |
     81 	 G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE)
     82       };
     83 
     84       info.value_table = &value_table;
     85 
     86       _mix_display_type = g_type_fundamental_next ();
     87       g_type_register_fundamental (_mix_display_type, "MixDisplay",
     88 				   &info, &fundamental_info,
     89 				   G_TYPE_FLAG_ABSTRACT);
     90 
     91     }
     92 
     93   return _mix_display_type;
     94 }
     95 
     96 static void
     97 mix_display_class_init (gpointer g_class, gpointer class_data)
     98 {
     99   MixDisplayClass *klass = MIX_DISPLAY_CLASS (g_class);
    100 
    101   klass->dup = mix_display_dup_default;
    102   klass->copy = mix_display_copy_default;
    103   klass->finalize = mix_display_finalize;
    104   klass->equal = mix_display_equal_default;
    105 }
    106 
    107 static void
    108 mix_display_init (GTypeInstance * instance, gpointer klass)
    109 {
    110   MixDisplay *obj = MIX_DISPLAY_CAST (instance);
    111 
    112   obj->refcount = 1;
    113 }
    114 
    115 gboolean
    116 mix_display_copy (MixDisplay * target, const MixDisplay * src)
    117 {
    118   /* Use the target object class. Because it knows what it is looking for. */
    119   MixDisplayClass *klass = MIX_DISPLAY_GET_CLASS (target);
    120   if (klass->copy)
    121     {
    122       return klass->copy (target, src);
    123     }
    124   else
    125     {
    126       return mix_display_copy_default (target, src);
    127     }
    128 }
    129 
    130 /**
    131 * mix_display_copy_default:
    132 * @target:
    133 * @src:
    134 *
    135 * The default copy method of this object. Perhap copy at this level.
    136 * Assign this to the copy vmethod.
    137 */
    138 static gboolean
    139 mix_display_copy_default (MixDisplay * target, const MixDisplay * src)
    140 {
    141   if (MIX_IS_DISPLAY (target) && MIX_IS_DISPLAY (src))
    142     {
    143       // TODO perform deep copy.
    144       return TRUE;
    145     }
    146   return FALSE;
    147 }
    148 
    149 static void
    150 mix_display_finalize (MixDisplay * obj)
    151 {
    152   /* do nothing */
    153 }
    154 
    155 MixDisplay *
    156 mix_display_dup (const MixDisplay * obj)
    157 {
    158   MixDisplayClass *klass = MIX_DISPLAY_GET_CLASS (obj);
    159 
    160   if (klass->dup)
    161     {
    162       return klass->dup (obj);
    163     }
    164   else if (MIX_IS_DISPLAY (obj))
    165     {
    166       return mix_display_dup_default (obj);
    167     }
    168   return NULL;
    169 }
    170 
    171 static MixDisplay *
    172 mix_display_dup_default (const MixDisplay * obj)
    173 {
    174   MixDisplay *ret = mix_display_new ();
    175   if (mix_display_copy (ret, obj))
    176     {
    177       return ret;
    178     }
    179 
    180   return NULL;
    181 }
    182 
    183 MixDisplay *
    184 mix_display_new (GType type)
    185 {
    186   MixDisplay *obj;
    187 
    188   /* we don't support dynamic types because they really aren't useful,
    189    * and could cause refcount problems */
    190   obj = (MixDisplay *) g_type_create_instance (type);
    191 
    192   return obj;
    193 }
    194 
    195 MixDisplay *
    196 mix_display_ref (MixDisplay * obj)
    197 {
    198   g_return_val_if_fail (MIX_IS_DISPLAY (obj), NULL);
    199 
    200   g_atomic_int_inc (&obj->refcount);
    201 
    202   return obj;
    203 }
    204 
    205 static void
    206 mix_display_free (MixDisplay * obj)
    207 {
    208   MixDisplayClass *klass = NULL;
    209 
    210   klass = MIX_DISPLAY_GET_CLASS (obj);
    211   klass->finalize (obj);
    212 
    213   /* Should we support recycling the object? */
    214   /* If so, refcount handling is slightly different. */
    215   /* i.e. If the refcount is still 0 we can really free the object, else the finalize method recycled the object -- but to where? */
    216 
    217   if (g_atomic_int_get (&obj->refcount) == 0)
    218     {
    219 
    220       g_type_free_instance ((GTypeInstance *) obj);
    221     }
    222 }
    223 
    224 void
    225 mix_display_unref (MixDisplay * obj)
    226 {
    227   g_return_if_fail (obj != NULL);
    228   g_return_if_fail (obj->refcount > 0);
    229 
    230   if (G_UNLIKELY (g_atomic_int_dec_and_test (&obj->refcount)))
    231     {
    232       mix_display_free (obj);
    233     }
    234 }
    235 
    236 static void
    237 mix_value_display_init (GValue * value)
    238 {
    239   value->data[0].v_pointer = NULL;
    240 }
    241 
    242 static void
    243 mix_value_display_free (GValue * value)
    244 {
    245   if (value->data[0].v_pointer)
    246     {
    247       mix_display_unref (MIX_DISPLAY_CAST (value->data[0].v_pointer));
    248     }
    249 }
    250 
    251 static void
    252 mix_value_display_copy (const GValue * src_value, GValue * dest_value)
    253 {
    254   if (src_value->data[0].v_pointer)
    255     {
    256       dest_value->data[0].v_pointer =
    257 	mix_display_ref (MIX_DISPLAY_CAST (src_value->data[0].v_pointer));
    258     }
    259   else
    260     {
    261       dest_value->data[0].v_pointer = NULL;
    262     }
    263 }
    264 
    265 static gpointer
    266 mix_value_display_peek_pointer (const GValue * value)
    267 {
    268   return value->data[0].v_pointer;
    269 }
    270 
    271 static gchar *
    272 mix_value_display_collect (GValue * value, guint n_collect_values,
    273 			   GTypeCValue * collect_values, guint collect_flags)
    274 {
    275   mix_value_set_display (value, collect_values[0].v_pointer);
    276 
    277   return NULL;
    278 }
    279 
    280 static gchar *
    281 mix_value_display_lcopy (const GValue * value,
    282 			 guint n_collect_values,
    283 			 GTypeCValue * collect_values, guint collect_flags)
    284 {
    285   gpointer *obj_p = collect_values[0].v_pointer;
    286 
    287   if (!obj_p)
    288     {
    289       return g_strdup_printf ("value location for '%s' passed as NULL",
    290 			      G_VALUE_TYPE_NAME (value));
    291     }
    292 
    293   if (!value->data[0].v_pointer)
    294     *obj_p = NULL;
    295   else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
    296     *obj_p = value->data[0].v_pointer;
    297   else
    298     *obj_p = mix_display_ref (value->data[0].v_pointer);
    299 
    300   return NULL;
    301 }
    302 
    303 /**
    304 * mix_value_set_display:
    305 * @value:       a valid #GValue of %MIX_TYPE_DISPLAY derived type
    306 * @obj: object value to set
    307 *
    308 * Set the contents of a %MIX_TYPE_DISPLAY derived #GValue to
    309 * @obj.
    310 * The caller retains ownership of the reference.
    311 */
    312 void
    313 mix_value_set_display (GValue * value, MixDisplay * obj)
    314 {
    315   gpointer *pointer_p;
    316 
    317   g_return_if_fail (MIX_VALUE_HOLDS_DISPLAY (value));
    318   g_return_if_fail (obj == NULL || MIX_IS_DISPLAY (obj));
    319 
    320   pointer_p = &value->data[0].v_pointer;
    321   mix_display_replace ((MixDisplay **) pointer_p, obj);
    322 }
    323 
    324 /**
    325 * mix_value_take_display:
    326 * @value: a valid #GValue of #MIX_TYPE_DISPLAY derived type
    327 * @obj: object value to take
    328 *
    329 * Set the contents of a #MIX_TYPE_DISPLAY derived #GValue to
    330 * @obj.
    331 * Takes over the ownership of the caller's reference to @obj;
    332 * the caller doesn't have to unref it any more.
    333 */
    334 void
    335 mix_value_take_display (GValue * value, MixDisplay * obj)
    336 {
    337   gpointer *pointer_p;
    338 
    339   g_return_if_fail (MIX_VALUE_HOLDS_DISPLAY (value));
    340   g_return_if_fail (obj == NULL || MIX_IS_DISPLAY (obj));
    341 
    342   pointer_p = &value->data[0].v_pointer;
    343   mix_display_replace ((MixDisplay **) pointer_p, obj);
    344   if (obj)
    345     mix_display_unref (obj);
    346 }
    347 
    348 /**
    349 * mix_value_get_display:
    350 * @value: a valid #GValue of #MIX_TYPE_DISPLAY derived type
    351 * @returns:object contents of @value
    352 *
    353 * refcount of the MixDisplay is not increased.
    354 */
    355 MixDisplay *
    356 mix_value_get_display (const GValue * value)
    357 {
    358   g_return_val_if_fail (MIX_VALUE_HOLDS_DISPLAY (value), NULL);
    359 
    360   return value->data[0].v_pointer;
    361 }
    362 
    363 /**
    364 * mix_value_dup_display:
    365 * @value:   a valid #GValue of %MIX_TYPE_DISPLAY derived type
    366 * @returns: object contents of @value
    367 *
    368 * refcount of MixDisplay is increased.
    369 */
    370 MixDisplay *
    371 mix_value_dup_display (const GValue * value)
    372 {
    373   g_return_val_if_fail (MIX_VALUE_HOLDS_DISPLAY (value), NULL);
    374 
    375   return mix_display_ref (value->data[0].v_pointer);
    376 }
    377 
    378 
    379 static void
    380 param_display_init (GParamSpec * pspec)
    381 {
    382   /* GParamSpecDisplay *ospec = G_PARAM_SPEC_DISPLAY (pspec); */
    383 }
    384 
    385 static void
    386 param_display_set_default (GParamSpec * pspec, GValue * value)
    387 {
    388   value->data[0].v_pointer = NULL;
    389 }
    390 
    391 static gboolean
    392 param_display_validate (GParamSpec * pspec, GValue * value)
    393 {
    394   gboolean validated = FALSE;
    395   MixParamSpecDisplay *ospec = MIX_PARAM_SPEC_DISPLAY (pspec);
    396   MixDisplay *obj = value->data[0].v_pointer;
    397 
    398   if (obj && !g_value_type_compatible (G_OBJECT_TYPE (obj), G_PARAM_SPEC_VALUE_TYPE (ospec)))
    399     {
    400       mix_display_unref (obj);
    401       value->data[0].v_pointer = NULL;
    402       validated = TRUE;
    403     }
    404 
    405   return validated;
    406 }
    407 
    408 static gint
    409 param_display_values_cmp (GParamSpec * pspec,
    410 			  const GValue * value1, const GValue * value2)
    411 {
    412   guint8 *p1 = value1->data[0].v_pointer;
    413   guint8 *p2 = value2->data[0].v_pointer;
    414 
    415 
    416   return p1 < p2 ? -1 : p1 > p2;
    417 }
    418 
    419 GType
    420 mix_param_spec_display_get_type (void)
    421 {
    422   static GType type;
    423 
    424   if (G_UNLIKELY (type) == 0)
    425     {
    426       static const GParamSpecTypeInfo pspec_info = {
    427 	sizeof (MixParamSpecDisplay),	/* instance_size */
    428 	16,			/* n_preallocs */
    429 	param_display_init,	/* instance_init */
    430 	G_TYPE_OBJECT,		/* value_type */
    431 	NULL,			/* finalize */
    432 	param_display_set_default,	/* value_set_default */
    433 	param_display_validate,	/* value_validate */
    434 	param_display_values_cmp,	/* values_cmp */
    435       };
    436       /* FIXME 0.11: Should really be MixParamSpecDisplay */
    437       type = g_param_type_register_static ("GParamSpecDisplay", &pspec_info);
    438     }
    439 
    440   return type;
    441 }
    442 
    443 /**
    444 * mix_param_spec_display:
    445 * @name: the canonical name of the property
    446 * @nick: the nickname of the property
    447 * @blurb: a short description of the property
    448 * @object_type: the #MixDisplayType for the property
    449 * @flags: a combination of #GParamFlags
    450 * @returns: a newly allocated #GParamSpec instance
    451 *
    452 * Creates a new #GParamSpec instance that hold #MixDisplay references.
    453 *
    454 */
    455 GParamSpec *
    456 mix_param_spec_display (const char *name, const char *nick,
    457 			const char *blurb, GType object_type,
    458 			GParamFlags flags)
    459 {
    460   MixParamSpecDisplay *ospec;
    461 
    462   g_return_val_if_fail (g_type_is_a (object_type, MIX_TYPE_DISPLAY), NULL);
    463 
    464   ospec = g_param_spec_internal (MIX_TYPE_PARAM_DISPLAY,
    465 				 name, nick, blurb, flags);
    466   G_PARAM_SPEC (ospec)->value_type = object_type;
    467 
    468   return G_PARAM_SPEC (ospec);
    469 }
    470 
    471 /**
    472 * mix_display_replace:
    473 * @olddata: pointer to a pointer to a object to be replaced
    474 * @newdata: pointer to new object
    475 *
    476 * Modifies a pointer to point to a new object.  The modification
    477 * is done atomically, and the reference counts are updated correctly.
    478 * Either @newdata and the value pointed to by @olddata may be NULL.
    479 */
    480 void
    481 mix_display_replace (MixDisplay ** olddata, MixDisplay * newdata)
    482 {
    483   MixDisplay *olddata_val;
    484 
    485   g_return_if_fail (olddata != NULL);
    486 
    487   olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
    488 
    489   if (olddata_val == newdata)
    490     return;
    491 
    492   if (newdata)
    493     mix_display_ref (newdata);
    494 
    495   while (!g_atomic_pointer_compare_and_exchange
    496 	 ((gpointer *) olddata, olddata_val, newdata))
    497     {
    498       olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
    499     }
    500 
    501   if (olddata_val)
    502     mix_display_unref (olddata_val);
    503 
    504 }
    505 
    506 gboolean
    507 mix_display_equal (MixDisplay * first, MixDisplay * second)
    508 {
    509   if (MIX_IS_DISPLAY (first))
    510     {
    511       MixDisplayClass *klass = MIX_DISPLAY_GET_CLASS (first);
    512 
    513       if (klass->equal)
    514 	{
    515 	  return klass->equal (first, second);
    516 	}
    517       else
    518 	{
    519 	  return mix_display_equal_default (first, second);
    520 	}
    521     }
    522   else
    523     return FALSE;
    524 }
    525 
    526 static gboolean
    527 mix_display_equal_default (MixDisplay * first, MixDisplay * second)
    528 {
    529   if (MIX_IS_DISPLAY (first) && MIX_IS_DISPLAY (second))
    530     {
    531       gboolean ret = TRUE;
    532 
    533       // Do data comparison here.
    534 
    535       return ret;
    536     }
    537   else
    538     return FALSE;
    539 }
    540