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