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 Intel’s 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
mix_display_get_type(void)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
mix_display_class_init(gpointer g_class,gpointer class_data)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
mix_display_init(GTypeInstance * instance,gpointer klass)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
mix_display_copy(MixDisplay * target,const MixDisplay * src)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
mix_display_copy_default(MixDisplay * target,const MixDisplay * src)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
mix_display_finalize(MixDisplay * obj)150 mix_display_finalize (MixDisplay * obj)
151 {
152   /* do nothing */
153 }
154 
155 MixDisplay *
mix_display_dup(const MixDisplay * obj)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 *
mix_display_dup_default(const MixDisplay * obj)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 *
mix_display_new(GType type)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 *
mix_display_ref(MixDisplay * obj)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
mix_display_free(MixDisplay * obj)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
mix_display_unref(MixDisplay * obj)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
mix_value_display_init(GValue * value)237 mix_value_display_init (GValue * value)
238 {
239   value->data[0].v_pointer = NULL;
240 }
241 
242 static void
mix_value_display_free(GValue * value)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
mix_value_display_copy(const GValue * src_value,GValue * dest_value)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
mix_value_display_peek_pointer(const GValue * value)266 mix_value_display_peek_pointer (const GValue * value)
267 {
268   return value->data[0].v_pointer;
269 }
270 
271 static gchar *
mix_value_display_collect(GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)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 *
mix_value_display_lcopy(const GValue * value,guint n_collect_values,GTypeCValue * collect_values,guint collect_flags)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
mix_value_set_display(GValue * value,MixDisplay * obj)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
mix_value_take_display(GValue * value,MixDisplay * obj)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 *
mix_value_get_display(const GValue * value)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 *
mix_value_dup_display(const GValue * value)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
param_display_init(GParamSpec * pspec)380 param_display_init (GParamSpec * pspec)
381 {
382   /* GParamSpecDisplay *ospec = G_PARAM_SPEC_DISPLAY (pspec); */
383 }
384 
385 static void
param_display_set_default(GParamSpec * pspec,GValue * value)386 param_display_set_default (GParamSpec * pspec, GValue * value)
387 {
388   value->data[0].v_pointer = NULL;
389 }
390 
391 static gboolean
param_display_validate(GParamSpec * pspec,GValue * value)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
param_display_values_cmp(GParamSpec * pspec,const GValue * value1,const GValue * value2)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
mix_param_spec_display_get_type(void)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 *
mix_param_spec_display(const char * name,const char * nick,const char * blurb,GType object_type,GParamFlags flags)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
mix_display_replace(MixDisplay ** olddata,MixDisplay * newdata)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
mix_display_equal(MixDisplay * first,MixDisplay * second)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
mix_display_equal_default(MixDisplay * first,MixDisplay * second)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