2 * Copyright © 2002 Jorn Baayen <jorn@nl.linux.org>
3 * Copyright © 2003 Marco Pesenti Gritti
4 * Copyright © 2003 Christian Persch
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * $Id: ephy-node.c 6952 2007-03-11 19:42:02Z chpe $
26 #include <glib/gi18n.h>
33 #include "ephy-node.h"
39 EphyNodeCallback callback
;
40 EphyNodeSignalType type
;
63 GPtrArray
*properties
;
71 guint invalidated_signals
;
72 guint is_drag_source
: 1;
73 guint is_drag_dest
: 1;
80 EphyNodeSignalType type
;
85 int_equal (gconstpointer a
,
88 return GPOINTER_TO_INT (a
) == GPOINTER_TO_INT (b
);
92 int_hash (gconstpointer a
)
94 return GPOINTER_TO_INT (a
);
98 callback (long id
, EphyNodeSignalData
*data
, gpointer
*dummy
)
100 ENESCData
*user_data
;
103 if (data
->invalidated
) return;
105 user_data
= (ENESCData
*) dummy
;
107 G_VA_COPY(valist
, user_data
->valist
);
109 if (data
->type
!= user_data
->type
) return;
113 case EPHY_NODE_DESTROY
:
114 case EPHY_NODE_RESTORED
:
115 data
->callback (data
->node
, data
->data
);
118 case EPHY_NODE_CHANGED
:
122 property_id
= va_arg (valist
, guint
);
124 data
->callback (data
->node
, property_id
, data
->data
);
128 case EPHY_NODE_CHILD_ADDED
:
132 node
= va_arg (valist
, EphyNode
*);
134 data
->callback (data
->node
, node
, data
->data
);
138 case EPHY_NODE_CHILD_CHANGED
:
143 node
= va_arg (valist
, EphyNode
*);
144 property_id
= va_arg (valist
, guint
);
146 data
->callback (data
->node
, node
, property_id
, data
->data
);
150 case EPHY_NODE_CHILD_REMOVED
:
155 node
= va_arg (valist
, EphyNode
*);
156 last_index
= va_arg (valist
, guint
);
158 data
->callback (data
->node
, node
, last_index
, data
->data
);
162 case EPHY_NODE_CHILDREN_REORDERED
:
163 data
->callback (data
->node
, va_arg (valist
, int *), data
->data
);
171 remove_invalidated_signals (long id
,
172 EphyNodeSignalData
*data
,
175 return data
->invalidated
;
179 ephy_node_emit_signal (EphyNode
*node
, EphyNodeSignalType type
, ...)
185 va_start (data
.valist
, type
);
189 g_hash_table_foreach (node
->signals
,
193 va_end (data
.valist
);
195 if (G_UNLIKELY (--node
->emissions
== 0 && node
->invalidated_signals
))
199 removed
= g_hash_table_foreach_remove
201 (GHRFunc
) remove_invalidated_signals
,
203 g_assert (removed
== node
->invalidated_signals
);
205 node
->invalidated_signals
= 0;
210 real_remove_child (EphyNode
*node
,
212 gboolean remove_from_parent
,
213 gboolean remove_from_child
)
215 EphyNodeParent
*node_info
;
217 node_info
= g_hash_table_lookup (child
->parents
,
218 GINT_TO_POINTER (node
->id
));
220 if (remove_from_parent
) {
224 old_index
= node_info
->index
;
226 g_ptr_array_remove_index (node
->children
,
229 /* correct indices on kids */
230 for (i
= node_info
->index
; i
< node
->children
->len
; i
++) {
231 EphyNode
*borked_node
;
232 EphyNodeParent
*borked_node_info
;
234 borked_node
= g_ptr_array_index (node
->children
, i
);
237 borked_node_info
= g_hash_table_lookup (borked_node
->parents
,
238 GINT_TO_POINTER (node
->id
));
239 borked_node_info
->index
--;
242 ephy_node_emit_signal (node
, EPHY_NODE_CHILD_REMOVED
, child
, old_index
);
245 if (remove_from_child
) {
246 g_hash_table_remove (child
->parents
,
247 GINT_TO_POINTER (node
->id
));
252 remove_child (long id
,
253 EphyNodeParent
*node_info
,
256 real_remove_child (node_info
->node
, node
, TRUE
, FALSE
);
260 signal_object_weak_notify (EphyNodeSignalData
*signal_data
,
261 GObject
*where_the_object_was
)
263 signal_data
->data
= NULL
;
264 ephy_node_signal_disconnect (signal_data
->node
, signal_data
->id
);
268 destroy_signal_data (EphyNodeSignalData
*signal_data
)
270 if (signal_data
->data
)
272 g_object_weak_unref (G_OBJECT (signal_data
->data
),
273 (GWeakNotify
)signal_object_weak_notify
,
277 g_slice_free (EphyNodeSignalData
, signal_data
);
281 node_parent_free (EphyNodeParent
*parent
)
283 g_slice_free (EphyNodeParent
, parent
);
287 ephy_node_destroy (EphyNode
*node
)
291 ephy_node_emit_signal (node
, EPHY_NODE_DESTROY
);
293 /* Remove from parents. */
294 g_hash_table_foreach (node
->parents
,
295 (GHFunc
) remove_child
,
297 g_hash_table_destroy (node
->parents
);
299 /* Remove children. */
300 for (i
= 0; i
< node
->children
->len
; i
++) {
303 child
= g_ptr_array_index (node
->children
, i
);
305 real_remove_child (node
, child
, FALSE
, TRUE
);
307 g_ptr_array_free (node
->children
, TRUE
);
309 /* Remove signals. */
310 g_hash_table_destroy (node
->signals
);
313 _ephy_node_db_remove_id (node
->db
, node
->id
);
315 /* Remove properties. */
316 for (i
= 0; i
< node
->properties
->len
; i
++) {
319 val
= g_ptr_array_index (node
->properties
, i
);
323 g_slice_free (GValue
, val
);
326 g_ptr_array_free (node
->properties
, TRUE
);
328 g_slice_free (EphyNode
, node
);
332 ephy_node_new (EphyNodeDb
*db
)
336 g_return_val_if_fail (EPHY_IS_NODE_DB (db
), NULL
);
338 if (ephy_node_db_is_immutable (db
)) return NULL
;
340 id
= _ephy_node_db_new_id (db
);
342 return ephy_node_new_with_id (db
, id
);
346 ephy_node_new_with_id (EphyNodeDb
*db
, guint reserved_id
)
350 g_return_val_if_fail (EPHY_IS_NODE_DB (db
), NULL
);
352 if (ephy_node_db_is_immutable (db
)) return NULL
;
354 node
= g_slice_new0 (EphyNode
);
358 node
->id
= reserved_id
;
362 node
->properties
= g_ptr_array_new ();
364 node
->children
= g_ptr_array_new ();
366 node
->parents
= g_hash_table_new_full
367 (int_hash
, int_equal
, NULL
, (GDestroyNotify
) node_parent_free
);
369 node
->signals
= g_hash_table_new_full
370 (int_hash
, int_equal
, NULL
,
371 (GDestroyNotify
)destroy_signal_data
);
375 node
->invalidated_signals
= 0;
376 node
->is_drag_source
= TRUE
;
377 node
->is_drag_dest
= TRUE
;
379 _ephy_node_db_add_id (db
, reserved_id
, node
);
385 ephy_node_get_db (EphyNode
*node
)
387 g_return_val_if_fail (EPHY_IS_NODE (node
), NULL
);
393 ephy_node_get_id (EphyNode
*node
)
397 g_return_val_if_fail (EPHY_IS_NODE (node
), G_MAXUINT
);
405 ephy_node_ref (EphyNode
*node
)
407 g_return_if_fail (EPHY_IS_NODE (node
));
413 ephy_node_unref (EphyNode
*node
)
415 g_return_if_fail (EPHY_IS_NODE (node
));
419 if (node
->ref_count
<= 0) {
420 ephy_node_destroy (node
);
425 child_changed (guint id
,
426 EphyNodeParent
*node_info
,
427 EphyNodeChange
*change
)
429 ephy_node_emit_signal (node_info
->node
, EPHY_NODE_CHILD_CHANGED
,
430 change
->node
, change
->property_id
);
434 real_set_property (EphyNode
*node
,
440 if (property_id
>= node
->properties
->len
) {
441 g_ptr_array_set_size (node
->properties
, property_id
+ 1);
444 old
= g_ptr_array_index (node
->properties
, property_id
);
447 g_slice_free (GValue
, old
);
450 g_ptr_array_index (node
->properties
, property_id
) = value
;
454 ephy_node_set_property_internal (EphyNode
*node
,
458 EphyNodeChange change
;
460 real_set_property (node
, property_id
, value
);
463 change
.property_id
= property_id
;
464 g_hash_table_foreach (node
->parents
,
465 (GHFunc
) child_changed
,
468 ephy_node_emit_signal (node
, EPHY_NODE_CHANGED
, property_id
);
473 ephy_node_set_property (EphyNode
*node
,
479 g_return_if_fail (EPHY_IS_NODE (node
));
480 g_return_if_fail (value
!= NULL
);
482 if (ephy_node_db_is_immutable (node
->db
)) return;
484 new = g_slice_new0 (GValue
);
485 g_value_init (new, G_VALUE_TYPE (value
));
486 g_value_copy (value
, new);
488 ephy_node_set_property_internal (node
, property_id
, new);
492 ephy_node_get_property (EphyNode
*node
,
498 g_return_val_if_fail (EPHY_IS_NODE (node
), FALSE
);
499 g_return_val_if_fail (value
!= NULL
, FALSE
);
501 if (property_id
>= node
->properties
->len
) {
505 ret
= g_ptr_array_index (node
->properties
, property_id
);
510 g_value_init (value
, G_VALUE_TYPE (ret
));
511 g_value_copy (ret
, value
);
517 ephy_node_set_property_string (EphyNode
*node
,
523 g_return_if_fail (EPHY_IS_NODE (node
));
525 if (ephy_node_db_is_immutable (node
->db
)) return;
527 new = g_slice_new0 (GValue
);
528 g_value_init (new, G_TYPE_STRING
);
529 g_value_set_string (new, value
);
531 ephy_node_set_property_internal (node
, property_id
, new);
535 ephy_node_get_property_string (EphyNode
*node
,
541 g_return_val_if_fail (EPHY_IS_NODE (node
), NULL
);
543 if (property_id
>= node
->properties
->len
) {
547 ret
= g_ptr_array_index (node
->properties
, property_id
);
552 retval
= g_value_get_string (ret
);
558 ephy_node_set_property_boolean (EphyNode
*node
,
564 g_return_if_fail (EPHY_IS_NODE (node
));
566 if (ephy_node_db_is_immutable (node
->db
)) return;
568 new = g_slice_new0 (GValue
);
569 g_value_init (new, G_TYPE_BOOLEAN
);
570 g_value_set_boolean (new, value
);
572 ephy_node_set_property_internal (node
, property_id
, new);
576 ephy_node_get_property_boolean (EphyNode
*node
,
582 g_return_val_if_fail (EPHY_IS_NODE (node
), FALSE
);
584 if (property_id
>= node
->properties
->len
) {
588 ret
= g_ptr_array_index (node
->properties
, property_id
);
593 retval
= g_value_get_boolean (ret
);
599 ephy_node_set_property_long (EphyNode
*node
,
605 g_return_if_fail (EPHY_IS_NODE (node
));
607 if (ephy_node_db_is_immutable (node
->db
)) return;
609 new = g_slice_new0 (GValue
);
610 g_value_init (new, G_TYPE_LONG
);
611 g_value_set_long (new, value
);
613 ephy_node_set_property_internal (node
, property_id
, new);
617 ephy_node_get_property_long (EphyNode
*node
,
623 g_return_val_if_fail (EPHY_IS_NODE (node
), -1);
625 if (property_id
>= node
->properties
->len
) {
629 ret
= g_ptr_array_index (node
->properties
, property_id
);
634 retval
= g_value_get_long (ret
);
640 ephy_node_set_property_int (EphyNode
*node
,
646 g_return_if_fail (EPHY_IS_NODE (node
));
648 if (ephy_node_db_is_immutable (node
->db
)) return;
650 new = g_slice_new0 (GValue
);
651 g_value_init (new, G_TYPE_INT
);
652 g_value_set_int (new, value
);
654 ephy_node_set_property_internal (node
, property_id
, new);
658 ephy_node_get_property_int (EphyNode
*node
,
664 g_return_val_if_fail (EPHY_IS_NODE (node
), -1);
666 if (property_id
>= node
->properties
->len
) {
670 ret
= g_ptr_array_index (node
->properties
, property_id
);
675 retval
= g_value_get_int (ret
);
681 ephy_node_set_property_double (EphyNode
*node
,
687 g_return_if_fail (EPHY_IS_NODE (node
));
689 if (ephy_node_db_is_immutable (node
->db
)) return;
691 new = g_slice_new0 (GValue
);
692 g_value_init (new, G_TYPE_DOUBLE
);
693 g_value_set_double (new, value
);
695 ephy_node_set_property_internal (node
, property_id
, new);
699 ephy_node_get_property_double (EphyNode
*node
,
705 g_return_val_if_fail (EPHY_IS_NODE (node
), -1);
707 if (property_id
>= node
->properties
->len
) {
711 ret
= g_ptr_array_index (node
->properties
, property_id
);
716 retval
= g_value_get_double (ret
);
722 ephy_node_set_property_float (EphyNode
*node
,
728 g_return_if_fail (EPHY_IS_NODE (node
));
730 if (ephy_node_db_is_immutable (node
->db
)) return;
732 new = g_slice_new0 (GValue
);
733 g_value_init (new, G_TYPE_FLOAT
);
734 g_value_set_float (new, value
);
736 ephy_node_set_property_internal (node
, property_id
, new);
740 ephy_node_get_property_float (EphyNode
*node
,
746 g_return_val_if_fail (EPHY_IS_NODE (node
), -1);
748 if (property_id
>= node
->properties
->len
) {
752 ret
= g_ptr_array_index (node
->properties
, property_id
);
757 retval
= g_value_get_float (ret
);
763 ephy_node_get_property_node (EphyNode
*node
,
769 g_return_val_if_fail (EPHY_IS_NODE (node
), NULL
);
770 g_return_val_if_fail (property_id
>= 0, NULL
);
772 if (property_id
>= node
->properties
->len
) {
776 ret
= g_ptr_array_index (node
->properties
, property_id
);
781 retval
= g_value_get_pointer (ret
);
788 xmlTextWriterPtr writer
;
793 write_parent (guint id
,
794 EphyNodeParent
*node_info
,
797 xmlTextWriterPtr writer
= data
->writer
;
799 /* there already was an error, do nothing. this works around
800 * the fact that g_hash_table_foreach cannot be cancelled.
802 if (data
->ret
< 0) return;
804 data
->ret
= xmlTextWriterStartElement (writer
, (const xmlChar
*)"parent");
805 if (data
->ret
< 0) return;
807 data
->ret
= xmlTextWriterWriteFormatAttribute
808 (writer
, (const xmlChar
*)"id", "%d", node_info
->node
->id
);
809 if (data
->ret
< 0) return;
811 data
->ret
= xmlTextWriterEndElement (writer
); /* parent */
812 if (data
->ret
< 0) return;
816 safe_write_string (xmlTextWriterPtr writer
,
817 const xmlChar
*string
)
825 /* http://www.w3.org/TR/REC-xml/#sec-well-formed :
827 [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] |
828 [#xE000-#xFFFD] | [#x10000-#x10FFFF]
829 any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
832 copy
= xmlStrdup (string
);
833 for (p
= copy
; *p
; p
++)
836 if (G_UNLIKELY (c
< 0x20 && c
!= 0xd && c
!= 0xa && c
!= 0x9)) {
841 ret
= xmlTextWriterWriteString (writer
, copy
);
848 ephy_node_write_to_xml(EphyNode
*node
,
849 xmlTextWriterPtr writer
)
851 xmlChar xml_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
856 g_return_val_if_fail (EPHY_IS_NODE (node
), -1);
857 g_return_val_if_fail (writer
!= NULL
, -1);
859 /* start writing the node */
860 ret
= xmlTextWriterStartElement (writer
, (const xmlChar
*)"node");
861 if (ret
< 0) goto out
;
864 ret
= xmlTextWriterWriteFormatAttribute (writer
, (const xmlChar
*)"id", "%d", node
->id
);
865 if (ret
< 0) goto out
;
867 /* write node properties */
868 for (i
= 0; i
< node
->properties
->len
; i
++)
872 value
= g_ptr_array_index (node
->properties
, i
);
874 if (value
== NULL
) continue;
875 if (G_VALUE_TYPE (value
) == G_TYPE_STRING
&&
876 g_value_get_string (value
) == NULL
) continue;
878 ret
= xmlTextWriterStartElement (writer
, (const xmlChar
*)"property");
881 ret
= xmlTextWriterWriteFormatAttribute (writer
, (const xmlChar
*)"id", "%d", i
);
884 ret
= xmlTextWriterWriteAttribute
885 (writer
, (const xmlChar
*)"value_type",
886 (const xmlChar
*)g_type_name (G_VALUE_TYPE (value
)));
889 switch (G_VALUE_TYPE (value
))
892 ret
= safe_write_string
893 (writer
, (const xmlChar
*)g_value_get_string (value
));
896 ret
= xmlTextWriterWriteFormatString
897 (writer
, "%d", g_value_get_boolean (value
));
900 ret
= xmlTextWriterWriteFormatString
901 (writer
, "%d", g_value_get_int (value
));
904 ret
= xmlTextWriterWriteFormatString
905 (writer
, "%ld", g_value_get_long (value
));
908 g_ascii_dtostr ((gchar
*)xml_buf
, sizeof (xml_buf
),
909 g_value_get_float (value
));
910 ret
= xmlTextWriterWriteString (writer
, xml_buf
);
913 g_ascii_dtostr ((gchar
*)xml_buf
, sizeof (xml_buf
),
914 g_value_get_double (value
));
915 ret
= xmlTextWriterWriteString (writer
, xml_buf
);
918 g_assert_not_reached ();
923 ret
= xmlTextWriterEndElement (writer
); /* property */
926 if (ret
< 0) goto out
;
928 /* now write parent node ids */
929 data
.writer
= writer
;
932 g_hash_table_foreach (node
->parents
,
933 (GHFunc
) write_parent
,
936 if (ret
< 0) goto out
;
938 ret
= xmlTextWriterEndElement (writer
); /* node */
939 if (ret
< 0) goto out
;
942 return ret
>= 0 ? 0 : -1;
946 real_add_child (EphyNode
*node
,
949 EphyNodeParent
*node_info
;
951 if (g_hash_table_lookup (child
->parents
,
952 GINT_TO_POINTER (node
->id
)) != NULL
) {
956 g_ptr_array_add (node
->children
, child
);
958 node_info
= g_slice_new0 (EphyNodeParent
);
959 node_info
->node
= node
;
960 node_info
->index
= node
->children
->len
- 1;
962 g_hash_table_insert (child
->parents
,
963 GINT_TO_POINTER (node
->id
),
968 ephy_node_new_from_xml (EphyNodeDb
*db
, xmlNodePtr xml_node
)
971 xmlNodePtr xml_child
;
975 g_return_val_if_fail (EPHY_IS_NODE_DB (db
), NULL
);
976 g_return_val_if_fail (xml_node
!= NULL
, NULL
);
978 if (ephy_node_db_is_immutable (db
)) return NULL
;
980 xml
= xmlGetProp (xml_node
, (const xmlChar
*)"id");
983 id
= atol ((const char *)xml
);
986 node
= ephy_node_new_with_id (db
, id
);
988 for (xml_child
= xml_node
->children
; xml_child
!= NULL
; xml_child
= xml_child
->next
) {
989 if (strcmp ((const char *)xml_child
->name
, "parent") == 0) {
993 xml
= xmlGetProp (xml_child
, (const xmlChar
*)"id");
994 g_assert (xml
!= NULL
);
995 parent_id
= atol ((const char *)xml
);
998 parent
= ephy_node_db_get_node_from_id (db
, parent_id
);
1002 real_add_child (parent
, node
);
1004 ephy_node_emit_signal (parent
, EPHY_NODE_CHILD_ADDED
, node
);
1006 } else if (strcmp ((const char *)xml_child
->name
, "property") == 0) {
1008 xmlChar
*xmlType
, *xmlValue
;
1011 xml
= xmlGetProp (xml_child
, (const xmlChar
*)"id");
1012 property_id
= atoi ((const char *)xml
);
1015 xmlType
= xmlGetProp (xml_child
, (const xmlChar
*)"value_type");
1016 xmlValue
= xmlNodeGetContent (xml_child
);
1018 value
= g_slice_new0 (GValue
);
1020 if (xmlStrEqual (xmlType
, (const xmlChar
*) "gchararray"))
1022 g_value_init (value
, G_TYPE_STRING
);
1023 g_value_set_string (value
, (const gchar
*)xmlValue
);
1025 else if (xmlStrEqual (xmlType
, (const xmlChar
*) "gint"))
1027 g_value_init (value
, G_TYPE_INT
);
1028 g_value_set_int (value
, atoi ((const char *)xmlValue
));
1030 else if (xmlStrEqual (xmlType
, (const xmlChar
*) "gboolean"))
1032 g_value_init (value
, G_TYPE_BOOLEAN
);
1033 g_value_set_boolean (value
, atoi ((const char *)xmlValue
));
1035 else if (xmlStrEqual (xmlType
, (const xmlChar
*) "glong"))
1037 g_value_init (value
, G_TYPE_LONG
);
1038 g_value_set_long (value
, atol ((const char *)xmlValue
));
1040 else if (xmlStrEqual (xmlType
, (const xmlChar
*) "gfloat"))
1042 g_value_init (value
, G_TYPE_FLOAT
);
1043 g_value_set_float (value
, g_ascii_strtod ((const gchar
*)xmlValue
, NULL
));
1045 else if (xmlStrEqual (xmlType
, (const xmlChar
*) "gdouble"))
1047 g_value_init (value
, G_TYPE_DOUBLE
);
1048 g_value_set_double (value
, g_ascii_strtod ((const gchar
*)xmlValue
, NULL
));
1050 else if (xmlStrEqual (xmlType
, (const xmlChar
*) "gpointer"))
1052 EphyNode
*property_node
;
1054 property_node
= ephy_node_db_get_node_from_id (db
, atol ((const char *)xmlValue
));
1056 g_value_set_pointer (value
, property_node
);
1061 g_assert_not_reached ();
1064 real_set_property (node
, property_id
, value
);
1071 ephy_node_emit_signal (node
, EPHY_NODE_RESTORED
);
1077 ephy_node_add_child (EphyNode
*node
,
1080 g_return_if_fail (EPHY_IS_NODE (node
));
1082 if (ephy_node_db_is_immutable (node
->db
)) return;
1084 real_add_child (node
, child
);
1086 ephy_node_emit_signal (node
, EPHY_NODE_CHILD_ADDED
, child
);
1090 ephy_node_remove_child (EphyNode
*node
,
1093 g_return_if_fail (EPHY_IS_NODE (node
));
1095 if (ephy_node_db_is_immutable (node
->db
)) return;
1097 real_remove_child (node
, child
, TRUE
, TRUE
);
1101 ephy_node_has_child (EphyNode
*node
,
1106 g_return_val_if_fail (EPHY_IS_NODE (node
), FALSE
);
1108 ret
= (g_hash_table_lookup (child
->parents
,
1109 GINT_TO_POINTER (node
->id
)) != NULL
);
1115 ephy_node_real_get_child_index (EphyNode
*node
,
1118 EphyNodeParent
*node_info
;
1121 node_info
= g_hash_table_lookup (child
->parents
,
1122 GINT_TO_POINTER (node
->id
));
1124 if (node_info
== NULL
)
1127 ret
= node_info
->index
;
1133 ephy_node_sort_children (EphyNode
*node
,
1134 GCompareFunc compare_func
)
1139 if (ephy_node_db_is_immutable (node
->db
)) return;
1141 g_return_if_fail (EPHY_IS_NODE (node
));
1142 g_return_if_fail (compare_func
!= NULL
);
1144 newkids
= g_ptr_array_new ();
1145 g_ptr_array_set_size (newkids
, node
->children
->len
);
1148 for (i
= 0; i
< node
->children
->len
; i
++)
1150 g_ptr_array_index (newkids
, i
) = g_ptr_array_index (node
->children
, i
);
1153 g_ptr_array_sort (newkids
, compare_func
);
1155 new_order
= g_new (int, newkids
->len
);
1156 memset (new_order
, -1, sizeof (int) * newkids
->len
);
1158 for (i
= 0; i
< newkids
->len
; i
++)
1160 EphyNodeParent
*node_info
;
1163 child
= g_ptr_array_index (newkids
, i
);
1164 new_order
[ephy_node_real_get_child_index (node
, child
)] = i
;
1165 node_info
= g_hash_table_lookup (child
->parents
,
1166 GINT_TO_POINTER (node
->id
));
1167 node_info
->index
= i
;
1170 g_ptr_array_free (node
->children
, FALSE
);
1171 node
->children
= newkids
;
1173 ephy_node_emit_signal (node
, EPHY_NODE_CHILDREN_REORDERED
, new_order
);
1179 ephy_node_reorder_children (EphyNode
*node
,
1185 g_return_if_fail (EPHY_IS_NODE (node
));
1186 g_return_if_fail (new_order
!= NULL
);
1188 if (ephy_node_db_is_immutable (node
->db
)) return;
1190 newkids
= g_ptr_array_new ();
1191 g_ptr_array_set_size (newkids
, node
->children
->len
);
1193 for (i
= 0; i
< node
->children
->len
; i
++) {
1195 EphyNodeParent
*node_info
;
1197 child
= g_ptr_array_index (node
->children
, i
);
1199 g_ptr_array_index (newkids
, new_order
[i
]) = child
;
1201 node_info
= g_hash_table_lookup (child
->parents
,
1202 GINT_TO_POINTER (node
->id
));
1203 node_info
->index
= new_order
[i
];
1206 g_ptr_array_free (node
->children
, FALSE
);
1207 node
->children
= newkids
;
1209 ephy_node_emit_signal (node
, EPHY_NODE_CHILDREN_REORDERED
, new_order
);
1213 ephy_node_get_children (EphyNode
*node
)
1215 g_return_val_if_fail (EPHY_IS_NODE (node
), NULL
);
1217 return node
->children
;
1221 ephy_node_get_n_children (EphyNode
*node
)
1225 g_return_val_if_fail (EPHY_IS_NODE (node
), -1);
1227 ret
= node
->children
->len
;
1233 ephy_node_get_nth_child (EphyNode
*node
,
1238 g_return_val_if_fail (EPHY_IS_NODE (node
), NULL
);
1239 g_return_val_if_fail (n
>= 0, NULL
);
1241 if (n
< node
->children
->len
) {
1242 ret
= g_ptr_array_index (node
->children
, n
);
1251 get_child_index_real (EphyNode
*node
,
1254 EphyNodeParent
*node_info
;
1256 node_info
= g_hash_table_lookup (child
->parents
,
1257 GINT_TO_POINTER (node
->id
));
1259 if (node_info
== NULL
)
1262 return node_info
->index
;
1267 ephy_node_get_child_index (EphyNode
*node
,
1272 g_return_val_if_fail (EPHY_IS_NODE (node
), -1);
1273 g_return_val_if_fail (EPHY_IS_NODE (child
), -1);
1275 ret
= ephy_node_real_get_child_index (node
, child
);
1281 ephy_node_get_next_child (EphyNode
*node
,
1287 g_return_val_if_fail (EPHY_IS_NODE (node
), NULL
);
1288 g_return_val_if_fail (EPHY_IS_NODE (child
), NULL
);
1290 idx
= get_child_index_real (node
, child
);
1292 if ((idx
+ 1) < node
->children
->len
) {
1293 ret
= g_ptr_array_index (node
->children
, idx
+ 1);
1302 ephy_node_get_previous_child (EphyNode
*node
,
1308 g_return_val_if_fail (EPHY_IS_NODE (node
), NULL
);
1309 g_return_val_if_fail (EPHY_IS_NODE (child
), NULL
);
1311 idx
= get_child_index_real (node
, child
);
1313 if ((idx
- 1) >= 0) {
1314 ret
= g_ptr_array_index (node
->children
, idx
- 1);
1323 ephy_node_signal_connect_object (EphyNode
*node
,
1324 EphyNodeSignalType type
,
1325 EphyNodeCallback callback
,
1328 EphyNodeSignalData
*signal_data
;
1331 g_return_val_if_fail (EPHY_IS_NODE (node
), -1);
1333 g_return_val_if_fail (node
->emissions
== 0, -1);
1335 signal_data
= g_slice_new0 (EphyNodeSignalData
);
1336 signal_data
->node
= node
;
1337 signal_data
->id
= node
->signal_id
;
1338 signal_data
->callback
= callback
;
1339 signal_data
->type
= type
;
1340 signal_data
->data
= object
;
1342 g_hash_table_insert (node
->signals
,
1343 GINT_TO_POINTER (node
->signal_id
),
1347 g_object_weak_ref (object
,
1348 (GWeakNotify
)signal_object_weak_notify
,
1352 ret
= node
->signal_id
;
1359 remove_matching_signal_data (gpointer key
,
1360 EphyNodeSignalData
*signal_data
,
1361 EphyNodeSignalData
*user_data
)
1363 return (user_data
->data
== signal_data
->data
&&
1364 user_data
->type
== signal_data
->type
&&
1365 user_data
->callback
== signal_data
->callback
);
1369 invalidate_matching_signal_data (gpointer key
,
1370 EphyNodeSignalData
*signal_data
,
1371 EphyNodeSignalData
*user_data
)
1373 if (user_data
->data
== signal_data
->data
&&
1374 user_data
->type
== signal_data
->type
&&
1375 user_data
->callback
== signal_data
->callback
&&
1376 !signal_data
->invalidated
)
1378 signal_data
->invalidated
= TRUE
;
1379 ++signal_data
->node
->invalidated_signals
;
1384 ephy_node_signal_disconnect_object (EphyNode
*node
,
1385 EphyNodeSignalType type
,
1386 EphyNodeCallback callback
,
1389 EphyNodeSignalData user_data
;
1391 g_return_val_if_fail (EPHY_IS_NODE (node
), 0);
1393 user_data
.callback
= callback
;
1394 user_data
.type
= type
;
1395 user_data
.data
= object
;
1397 if (G_LIKELY (node
->emissions
== 0))
1399 return g_hash_table_foreach_remove (node
->signals
,
1400 (GHRFunc
) remove_matching_signal_data
,
1405 g_hash_table_foreach (node
->signals
,
1406 (GHFunc
) invalidate_matching_signal_data
,
1413 ephy_node_signal_disconnect (EphyNode
*node
,
1416 g_return_if_fail (EPHY_IS_NODE (node
));
1417 g_return_if_fail (signal_id
!= -1);
1419 if (G_LIKELY (node
->emissions
== 0))
1421 g_hash_table_remove (node
->signals
,
1422 GINT_TO_POINTER (signal_id
));
1426 EphyNodeSignalData
*data
;
1428 data
= g_hash_table_lookup (node
->signals
,
1429 GINT_TO_POINTER (signal_id
));
1430 g_return_if_fail (data
!= NULL
);
1431 g_return_if_fail (!data
->invalidated
);
1433 data
->invalidated
= TRUE
;
1434 node
->invalidated_signals
++;
1439 ephy_node_set_is_drag_source (EphyNode
*node
,
1442 node
->is_drag_source
= allow
!= FALSE
;
1446 ephy_node_get_is_drag_source (EphyNode
*node
)
1448 return node
->is_drag_source
;
1452 ephy_node_set_is_drag_dest (EphyNode
*node
,
1455 node
->is_drag_dest
= allow
!= FALSE
;
1459 ephy_node_get_is_drag_dest (EphyNode
*node
)
1461 return node
->is_drag_dest
;
1465 ephy_node_get_type (void)
1467 static GType type
= 0;
1469 if (G_UNLIKELY (type
== 0))
1471 type
= g_boxed_type_register_static ("EphyNode",
1472 (GBoxedCopyFunc
) ephy_node_ref
,
1473 (GBoxedFreeFunc
) ephy_node_unref
);