]> Pileus Git - ~andy/gtk/blob - gtk/gtkstyleset.c
Remove gtkalias from style context code.
[~andy/gtk] / gtk / gtkstyleset.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <stdlib.h>
23 #include <gobject/gvaluecollector.h>
24
25 #include "gtkstyleprovider.h"
26 #include "gtkstyleset.h"
27 #include "gtkprivate.h"
28 #include "gtkthemingengine.h"
29 #include "gtkanimationdescription.h"
30 #include "gtkintl.h"
31
32 typedef struct GtkStyleSetPrivate GtkStyleSetPrivate;
33 typedef struct PropertyData PropertyData;
34 typedef struct PropertyNode PropertyNode;
35 typedef struct ValueData ValueData;
36
37 struct PropertyNode
38 {
39   GQuark property_quark;
40   GType property_type;
41   GValue default_value;
42   GtkStylePropertyParser parse_func;
43 };
44
45 struct ValueData
46 {
47   GtkStateFlags state;
48   GValue value;
49 };
50
51 struct PropertyData
52 {
53   GArray *values;
54 };
55
56 struct GtkStyleSetPrivate
57 {
58   GHashTable *color_map;
59   GHashTable *properties;
60 };
61
62 static GArray *properties = NULL;
63
64 static void gtk_style_set_provider_init (GtkStyleProviderIface *iface);
65 static void gtk_style_set_finalize      (GObject      *object);
66
67
68 G_DEFINE_TYPE_EXTENDED (GtkStyleSet, gtk_style_set, G_TYPE_OBJECT, 0,
69                         G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER,
70                                                gtk_style_set_provider_init));
71
72 static void
73 gtk_style_set_class_init (GtkStyleSetClass *klass)
74 {
75   GObjectClass *object_class = G_OBJECT_CLASS (klass);
76   GValue val = { 0 };
77
78   object_class->finalize = gtk_style_set_finalize;
79
80   /* Initialize default property set */
81   gtk_style_set_register_property ("foreground-color", GDK_TYPE_COLOR, NULL, NULL);
82   gtk_style_set_register_property ("background-color", GDK_TYPE_COLOR, NULL, NULL);
83   gtk_style_set_register_property ("text-color", GDK_TYPE_COLOR, NULL, NULL);
84   gtk_style_set_register_property ("base-color", GDK_TYPE_COLOR, NULL, NULL);
85
86   gtk_style_set_register_property ("font", PANGO_TYPE_FONT_DESCRIPTION, NULL, NULL);
87
88   gtk_style_set_register_property ("padding", GTK_TYPE_BORDER, NULL, NULL);
89   gtk_style_set_register_property ("border", G_TYPE_INT, NULL, NULL);
90
91   g_value_init (&val, GTK_TYPE_THEMING_ENGINE);
92   g_value_set_object (&val, (GObject *) gtk_theming_engine_load (NULL));
93   gtk_style_set_register_property ("engine", GTK_TYPE_THEMING_ENGINE, &val, NULL);
94   g_value_unset (&val);
95
96   g_value_init (&val, GTK_TYPE_ANIMATION_DESCRIPTION);
97   g_value_take_boxed (&val, gtk_animation_description_new (0, GTK_TIMELINE_PROGRESS_LINEAR));
98   gtk_style_set_register_property ("transition", GTK_TYPE_ANIMATION_DESCRIPTION, &val, NULL);
99   g_value_unset (&val);
100
101   g_type_class_add_private (object_class, sizeof (GtkStyleSetPrivate));
102 }
103
104 static PropertyData *
105 property_data_new (void)
106 {
107   PropertyData *data;
108
109   data = g_slice_new0 (PropertyData);
110   data->values = g_array_new (FALSE, FALSE, sizeof (ValueData));
111
112   return data;
113 }
114
115 static void
116 property_data_free (PropertyData *data)
117 {
118   guint i;
119
120   for (i = 0; i < data->values->len; i++)
121     {
122       ValueData *value_data;
123
124       value_data = &g_array_index (data->values, ValueData, i);
125
126       if (G_IS_VALUE (&value_data->value))
127         g_value_unset (&value_data->value);
128     }
129
130   g_array_free (data->values, TRUE);
131   g_slice_free (PropertyData, data);
132 }
133
134 static gboolean
135 property_data_find_position (PropertyData  *data,
136                              GtkStateFlags  state,
137                              guint         *pos)
138 {
139   gint min, max, mid;
140   gboolean found = FALSE;
141   guint position;
142
143   if (pos)
144     *pos = 0;
145
146   if (data->values->len == 0)
147     return FALSE;
148
149   /* Find position for the given state, or the position where
150    * it would be if not found, the array is ordered by the
151    * state flags.
152    */
153   min = 0;
154   max = data->values->len - 1;
155
156   do
157     {
158       ValueData *value_data;
159
160       mid = (min + max) / 2;
161       value_data = &g_array_index (data->values, ValueData, mid);
162
163       if (value_data->state == state)
164         {
165           found = TRUE;
166           position = mid;
167         }
168       else if (value_data->state < state)
169           position = min = mid + 1;
170       else
171         {
172           max = mid - 1;
173           position = mid;
174         }
175     }
176   while (!found && min <= max);
177
178   if (pos)
179     *pos = position;
180
181   return found;
182 }
183
184 static GValue *
185 property_data_get_value (PropertyData  *data,
186                          GtkStateFlags  state)
187 {
188   ValueData *val_data;
189   guint pos;
190
191   if (!property_data_find_position (data, state, &pos))
192     {
193       ValueData new = { 0 };
194
195       //val_data = &g_array_index (data->values, ValueData, pos);
196       new.state = state;
197       g_array_insert_val (data->values, pos, new);
198     }
199
200   val_data = &g_array_index (data->values, ValueData, pos);
201
202   return &val_data->value;
203 }
204
205 static GValue *
206 property_data_match_state (PropertyData  *data,
207                            GtkStateFlags  state)
208 {
209   guint pos;
210   gint i;
211
212   if (property_data_find_position (data, state, &pos))
213     {
214       ValueData *val_data;
215
216       /* Exact match */
217       val_data = &g_array_index (data->values, ValueData, pos);
218       return &val_data->value;
219     }
220
221   if (pos >= data->values->len)
222     pos = data->values->len - 1;
223
224   /* No exact match, go downwards the list to find
225    * the closest match to the given state flags, as
226    * a side effect, there is an implicit precedence
227    * of higher flags over the smaller ones.
228    */
229   for (i = pos; i >= 0; i--)
230     {
231       ValueData *val_data;
232
233       val_data = &g_array_index (data->values, ValueData, i);
234
235        /* Check whether any of the requested
236         * flags are set, and no other flags are.
237         *
238         * Also, no flags acts as a wildcard, such
239         * value should be always in the first position
240         * in the array (if present) anyways.
241         */
242       if (val_data->state == 0 ||
243           ((val_data->state & state) != 0 &&
244            (val_data->state & ~state) == 0))
245         return &val_data->value;
246     }
247
248   return NULL;
249 }
250
251 static void
252 gtk_style_set_init (GtkStyleSet *set)
253 {
254   GtkStyleSetPrivate *priv;
255
256   priv = set->priv = G_TYPE_INSTANCE_GET_PRIVATE (set,
257                                                   GTK_TYPE_STYLE_SET,
258                                                   GtkStyleSetPrivate);
259
260   priv->properties = g_hash_table_new_full (NULL, NULL, NULL,
261                                             (GDestroyNotify) property_data_free);
262 }
263
264 static void
265 gtk_style_set_finalize (GObject *object)
266 {
267   GtkStyleSetPrivate *priv;
268   GtkStyleSet *set;
269
270   set = GTK_STYLE_SET (object);
271   priv = set->priv;
272   g_hash_table_destroy (priv->properties);
273
274   if (priv->color_map)
275     g_hash_table_destroy (priv->color_map);
276
277   G_OBJECT_CLASS (gtk_style_set_parent_class)->finalize (object);
278 }
279
280 GtkStyleSet *
281 gtk_style_set_get_style (GtkStyleProvider *provider,
282                          GtkWidgetPath    *path)
283 {
284   /* Return style set itself */
285   return g_object_ref (provider);
286 }
287
288 static void
289 gtk_style_set_provider_init (GtkStyleProviderIface *iface)
290 {
291   iface->get_style = gtk_style_set_get_style;
292 }
293
294 static int
295 compare_property (gconstpointer p1,
296                   gconstpointer p2)
297 {
298   PropertyNode *key = (PropertyNode *) p1;
299   PropertyNode *node = (PropertyNode *) p2;
300
301   return (int) key->property_quark - node->property_quark;
302 }
303
304 static PropertyNode *
305 property_node_lookup (GQuark quark)
306 {
307   PropertyNode key = { 0 };
308
309   if (!quark)
310     return NULL;
311
312   if (!properties)
313     return NULL;
314
315   key.property_quark = quark;
316
317   return bsearch (&key, properties->data, properties->len,
318                   sizeof (PropertyNode), compare_property);
319 }
320
321 /* Property registration functions */
322 void
323 gtk_style_set_register_property (const gchar            *property_name,
324                                  GType                   type,
325                                  const GValue           *default_value,
326                                  GtkStylePropertyParser  parse_func)
327 {
328   PropertyNode *node, new = { 0 };
329   GQuark quark;
330   gint i;
331
332   g_return_if_fail (property_name != NULL);
333   g_return_if_fail (type != 0);
334
335   if (G_UNLIKELY (!properties))
336     properties = g_array_new (FALSE, TRUE, sizeof (PropertyNode));
337
338   quark = g_quark_try_string (property_name);
339
340   if ((node = property_node_lookup (quark)) != NULL)
341     {
342       g_warning ("Property \"%s\" was already registered with type %s",
343                  property_name, g_type_name (node->property_type));
344       return;
345     }
346
347   quark = g_quark_from_string (property_name);
348
349   new.property_quark = quark;
350   new.property_type = type;
351
352   if (default_value)
353     {
354       g_value_init (&new.default_value, G_VALUE_TYPE (default_value));
355       g_value_copy (default_value, &new.default_value);
356     }
357
358   if (parse_func)
359     new.parse_func = parse_func;
360
361   for (i = 0; i < properties->len; i++)
362     {
363       node = &g_array_index (properties, PropertyNode, i);
364
365       if (node->property_quark > quark)
366         break;
367     }
368
369   g_array_insert_val (properties, i, new);
370 }
371
372 gboolean
373 gtk_style_set_lookup_property (const gchar            *property_name,
374                                GType                  *type,
375                                GtkStylePropertyParser *parse_func)
376 {
377   PropertyNode *node;
378   GtkStyleSetClass *klass;
379   gboolean found = FALSE;
380   GQuark quark;
381   gint i;
382
383   g_return_val_if_fail (property_name != NULL, FALSE);
384
385   klass = g_type_class_ref (GTK_TYPE_STYLE_SET);
386   quark = g_quark_try_string (property_name);
387
388   if (quark == 0)
389     {
390       g_type_class_unref (klass);
391       return FALSE;
392     }
393
394   for (i = 0; i < properties->len; i++)
395     {
396       node = &g_array_index (properties, PropertyNode, i);
397
398       if (node->property_quark == quark)
399         {
400           if (type)
401             *type = node->property_type;
402
403           if (parse_func)
404             *parse_func = node->parse_func;
405
406           found = TRUE;
407           break;
408         }
409       else if (node->property_quark > quark)
410         break;
411     }
412
413   g_type_class_unref (klass);
414
415   return found;
416 }
417
418 /* GtkStyleSet methods */
419
420 GtkStyleSet *
421 gtk_style_set_new (void)
422 {
423   return g_object_new (GTK_TYPE_STYLE_SET, NULL);
424 }
425
426 void
427 gtk_style_set_map_color (GtkStyleSet      *set,
428                          const gchar      *name,
429                          GtkSymbolicColor *color)
430 {
431   GtkStyleSetPrivate *priv;
432
433   g_return_if_fail (GTK_IS_STYLE_SET (set));
434   g_return_if_fail (name != NULL);
435   g_return_if_fail (color != NULL);
436
437   priv = set->priv;
438
439   if (G_UNLIKELY (!priv->color_map))
440     priv->color_map = g_hash_table_new_full (g_str_hash,
441                                              g_str_equal,
442                                              (GDestroyNotify) g_free,
443                                              (GDestroyNotify) gtk_symbolic_color_unref);
444
445   g_hash_table_replace (priv->color_map,
446                         g_strdup (name),
447                         gtk_symbolic_color_ref (color));
448 }
449
450 GtkSymbolicColor *
451 gtk_style_set_lookup_color (GtkStyleSet *set,
452                             const gchar *name)
453 {
454   GtkStyleSetPrivate *priv;
455
456   g_return_val_if_fail (GTK_IS_STYLE_SET (set), NULL);
457   g_return_val_if_fail (name != NULL, NULL);
458
459   priv = set->priv;
460
461   if (!priv->color_map)
462     return NULL;
463
464   return g_hash_table_lookup (priv->color_map, name);
465 }
466
467 void
468 gtk_style_set_set_property (GtkStyleSet   *set,
469                             const gchar   *property,
470                             GtkStateFlags  state,
471                             const GValue  *value)
472 {
473   GtkStyleSetPrivate *priv;
474   PropertyNode *node;
475   PropertyData *prop;
476   GType value_type;
477   GValue *val;
478
479   g_return_if_fail (GTK_IS_STYLE_SET (set));
480   g_return_if_fail (property != NULL);
481   g_return_if_fail (value != NULL);
482
483   value_type = G_VALUE_TYPE (value);
484   node = property_node_lookup (g_quark_try_string (property));
485
486   if (!node)
487     {
488       g_warning ("Style property \"%s\" is not registered", property);
489       return;
490     }
491
492   if (node->property_type == GDK_TYPE_COLOR)
493     {
494       /* Allow GtkSymbolicColor as well */
495       g_return_if_fail (value_type == GDK_TYPE_COLOR || value_type == GTK_TYPE_SYMBOLIC_COLOR);
496     }
497   else
498     g_return_if_fail (node->property_type == value_type);
499
500   priv = set->priv;
501   prop = g_hash_table_lookup (priv->properties,
502                               GINT_TO_POINTER (node->property_quark));
503
504   if (!prop)
505     {
506       prop = property_data_new ();
507       g_hash_table_insert (priv->properties,
508                            GINT_TO_POINTER (node->property_quark),
509                            prop);
510     }
511
512   val = property_data_get_value (prop, state);
513
514   if (G_VALUE_TYPE (val) == value_type)
515     g_value_reset (val);
516   else
517     {
518       if (G_IS_VALUE (val))
519         g_value_unset (val);
520
521       g_value_init (val, value_type);
522     }
523
524   g_value_copy (value, val);
525 }
526
527 void
528 gtk_style_set_set_valist (GtkStyleSet   *set,
529                           GtkStateFlags  state,
530                           va_list        args)
531 {
532   GtkStyleSetPrivate *priv;
533   const gchar *property_name;
534
535   g_return_if_fail (GTK_IS_STYLE_SET (set));
536
537   priv = set->priv;
538   property_name = va_arg (args, const gchar *);
539
540   while (property_name)
541     {
542       PropertyNode *node;
543       PropertyData *prop;
544       gchar *error = NULL;
545       GValue *val;
546
547       node = property_node_lookup (g_quark_try_string (property_name));
548
549       if (!node)
550         {
551           g_warning ("Style property \"%s\" is not registered", property_name);
552           break;
553         }
554
555       prop = g_hash_table_lookup (priv->properties,
556                                   GINT_TO_POINTER (node->property_quark));
557
558       if (!prop)
559         {
560           prop = property_data_new ();
561           g_hash_table_insert (priv->properties,
562                                GINT_TO_POINTER (node->property_quark),
563                                prop);
564         }
565
566       val = property_data_get_value (prop, state);
567
568       if (G_IS_VALUE (val))
569         g_value_unset (val);
570
571       g_value_init (val, node->property_type);
572       G_VALUE_COLLECT (val, args, 0, &error);
573
574       if (error)
575         {
576           g_warning ("Could not set style property \"%s\": %s", property_name, error);
577           g_value_unset (val);
578           g_free (error);
579           break;
580         }
581
582       property_name = va_arg (args, const gchar *);
583     }
584 }
585
586 void
587 gtk_style_set_set (GtkStyleSet   *set,
588                    GtkStateFlags  state,
589                    ...)
590 {
591   va_list args;
592
593   g_return_if_fail (GTK_IS_STYLE_SET (set));
594
595   va_start (args, state);
596   gtk_style_set_set_valist (set, state, args);
597   va_end (args);
598 }
599
600 static gboolean
601 resolve_color (GtkStyleSet *set,
602                GValue      *value)
603 {
604   GdkColor color;
605
606   /* Resolve symbolic color to GdkColor */
607   if (!gtk_symbolic_color_resolve (g_value_get_boxed (value), set, &color))
608     return FALSE;
609
610   /* Store it back, this is where GdkColor caching happens */
611   g_value_unset (value);
612   g_value_init (value, GDK_TYPE_COLOR);
613   g_value_set_boxed (value, &color);
614
615   return TRUE;
616 }
617
618 gboolean
619 gtk_style_set_get_property (GtkStyleSet   *set,
620                             const gchar   *property,
621                             GtkStateFlags  state,
622                             GValue        *value)
623 {
624   GtkStyleSetPrivate *priv;
625   PropertyNode *node;
626   PropertyData *prop;
627   GValue *val;
628
629   g_return_val_if_fail (GTK_IS_STYLE_SET (set), FALSE);
630   g_return_val_if_fail (property != NULL, FALSE);
631   g_return_val_if_fail (value != NULL, FALSE);
632
633   node = property_node_lookup (g_quark_try_string (property));
634
635   if (!node)
636     {
637       g_warning ("Style property \"%s\" is not registered", property);
638       return FALSE;
639     }
640
641   priv = set->priv;
642   prop = g_hash_table_lookup (priv->properties,
643                               GINT_TO_POINTER (node->property_quark));
644
645   if (!prop)
646     return FALSE;
647
648   g_value_init (value, node->property_type);
649
650   val = property_data_match_state (prop, state);
651
652   if (!val && G_IS_VALUE (&node->default_value))
653     val = &node->default_value;
654
655   g_return_val_if_fail (G_IS_VALUE (val), FALSE);
656
657   if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR)
658     {
659       g_return_val_if_fail (node->property_type == GDK_TYPE_COLOR, FALSE);
660
661       if (!resolve_color (set, val))
662         return FALSE;
663     }
664
665   g_value_copy (val, value);
666
667   return TRUE;
668 }
669
670 void
671 gtk_style_set_get_valist (GtkStyleSet   *set,
672                           GtkStateFlags  state,
673                           va_list        args)
674 {
675   GtkStyleSetPrivate *priv;
676   const gchar *property_name;
677
678   g_return_if_fail (GTK_IS_STYLE_SET (set));
679
680   priv = set->priv;
681   property_name = va_arg (args, const gchar *);
682
683   while (property_name)
684     {
685       PropertyNode *node;
686       PropertyData *prop;
687       gchar *error = NULL;
688
689       node = property_node_lookup (g_quark_try_string (property_name));
690
691       if (!node)
692         {
693           g_warning ("Style property \"%s\" is not registered", property_name);
694           break;
695         }
696
697       prop = g_hash_table_lookup (priv->properties,
698                                   GINT_TO_POINTER (node->property_quark));
699
700       if (!prop && !G_IS_VALUE (&node->default_value))
701         {
702           GValue *empty_value = { 0 };
703
704           g_warning ("No value for style property \"%s\"", property_name);
705
706           g_value_init (&empty_value, node->property_type);
707           G_VALUE_LCOPY (&empty_value, args, 0, &error);
708         }
709       else
710         {
711           GValue *val = NULL;
712
713           if (prop)
714             val = property_data_match_state (prop, state);
715
716           if (!val && G_IS_VALUE (&node->default_value))
717             val = &node->default_value;
718
719           if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR)
720             {
721               g_return_if_fail (node->property_type == GDK_TYPE_COLOR);
722
723               if (!resolve_color (set, val))
724                 return;
725             }
726
727           G_VALUE_LCOPY (val, args, 0, &error);
728         }
729
730       if (error)
731         {
732           g_warning ("Could not get style property \"%s\": %s", property_name, error);
733           g_free (error);
734           break;
735         }
736
737       property_name = va_arg (args, const gchar *);
738     }
739 }
740
741 void
742 gtk_style_set_get (GtkStyleSet   *set,
743                    GtkStateFlags  state,
744                    ...)
745 {
746   va_list args;
747
748   g_return_if_fail (GTK_IS_STYLE_SET (set));
749
750   va_start (args, state);
751   gtk_style_set_get_valist (set, state, args);
752   va_end (args);
753 }
754
755 void
756 gtk_style_set_unset_property (GtkStyleSet   *set,
757                               const gchar   *property,
758                               GtkStateFlags  state)
759 {
760   GtkStyleSetPrivate *priv;
761   PropertyNode *node;
762   PropertyData *prop;
763   guint pos;
764
765   g_return_if_fail (GTK_IS_STYLE_SET (set));
766   g_return_if_fail (property != NULL);
767
768   node = property_node_lookup (g_quark_try_string (property));
769
770   if (!node)
771     {
772       g_warning ("Style property \"%s\" is not registered", property);
773       return;
774     }
775
776   priv = set->priv;
777   prop = g_hash_table_lookup (priv->properties,
778                               GINT_TO_POINTER (node->property_quark));
779
780   if (!prop)
781     return;
782
783   if (property_data_find_position (prop, state, &pos))
784     {
785       ValueData *data;
786
787       data = &g_array_index (prop->values, ValueData, pos);
788
789       if (G_IS_VALUE (&data->value))
790         g_value_unset (&data->value);
791
792       g_array_remove_index (prop->values, pos);
793     }
794 }
795
796 void
797 gtk_style_set_clear (GtkStyleSet *set)
798 {
799   GtkStyleSetPrivate *priv;
800
801   g_return_if_fail (GTK_IS_STYLE_SET (set));
802
803   priv = set->priv;
804   g_hash_table_remove_all (priv->properties);
805 }
806
807 void
808 gtk_style_set_merge (GtkStyleSet       *set,
809                      const GtkStyleSet *set_to_merge,
810                      gboolean           replace)
811 {
812   GtkStyleSetPrivate *priv, *priv_to_merge;
813   GHashTableIter iter;
814   gpointer key, value;
815
816   g_return_if_fail (GTK_IS_STYLE_SET (set));
817   g_return_if_fail (GTK_IS_STYLE_SET (set_to_merge));
818
819   priv = set->priv;
820   priv_to_merge = set_to_merge->priv;
821
822   /* Merge symbolic color map */
823   if (priv_to_merge->color_map)
824     {
825       g_hash_table_iter_init (&iter, priv_to_merge->color_map);
826
827       while (g_hash_table_iter_next (&iter, &key, &value))
828         {
829           const gchar *name;
830           GtkSymbolicColor *color;
831
832           name = key;
833           color = value;
834
835           if (!replace &&
836               g_hash_table_lookup (priv->color_map, name))
837             continue;
838
839           gtk_style_set_map_color (set, name, color);
840         }
841     }
842
843   /* Merge symbolic style properties */
844   g_hash_table_iter_init (&iter, priv_to_merge->properties);
845
846   while (g_hash_table_iter_next (&iter, &key, &value))
847     {
848       PropertyData *prop_to_merge = value;
849       PropertyData *prop;
850       guint i;
851
852       prop = g_hash_table_lookup (priv->properties, key);
853
854       if (!prop)
855         {
856           prop = property_data_new ();
857           g_hash_table_insert (priv->properties, key, prop);
858         }
859
860       for (i = 0; i < prop_to_merge->values->len; i++)
861         {
862           ValueData *data;
863           GValue *value;
864
865           data = &g_array_index (prop_to_merge->values, ValueData, i);
866           value = property_data_get_value (prop, data->state);
867
868           if (replace || !G_IS_VALUE (value))
869             {
870               if (!G_IS_VALUE (value))
871                 g_value_init (value, G_VALUE_TYPE (&data->value));
872               else if (G_VALUE_TYPE (value) != G_VALUE_TYPE (&data->value))
873                 {
874                   g_value_unset (value);
875                   g_value_init (value, G_VALUE_TYPE (&data->value));
876                 }
877
878               g_value_copy (&data->value, value);
879             }
880         }
881     }
882 }