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