gtk2/gtk/gtksequence.c
Søren Sandmann 38df3fec77 Replace broken, overly clever implementation with one that works.
Sat Oct 23 16:07:46 2004  Søren Sandmann  <sandmann@redhat.com>

	* gtk/gtksequence.c (_gtk_sequence_swap): Replace broken, overly
	clever implementation with one that works.

	* gtk/gtkliststore.c (gtk_list_store_swap): emit "rows_reordered"
	instead of "changed" twice.

	Bug 153479
2004-10-23 20:10:40 +00:00

1132 lines
24 KiB
C

/* GLIB - Library of useful routines for C programming
* Copyright (C) 2002 Soeren Sandmann (sandmann@daimi.au.dk)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <glib.h>
#include "gtksequence.h"
typedef struct _GtkSequenceNode GtkSequenceNode;
struct _GtkSequence {
GtkSequenceNode *node; /* does not necessarily point to the root.
* You can splay it if you want it to
*/
GDestroyNotify data_destroy_notify;
};
struct _GtkSequenceNode {
guint is_end : 1;
gint n_nodes : 31; /* number of nodes below this node,
* including this node
*/
GtkSequenceNode *parent;
GtkSequenceNode *left;
GtkSequenceNode *right;
GtkSequence *sequence;
gpointer data;
};
static GtkSequenceNode *_gtk_sequence_node_new (gpointer data);
static GtkSequenceNode *_gtk_sequence_node_find_first (GtkSequenceNode *node);
static GtkSequenceNode *_gtk_sequence_node_find_last (GtkSequenceNode *node);
static GtkSequenceNode *_gtk_sequence_node_find_by_pos (GtkSequenceNode *node,
gint pos);
static GtkSequenceNode *_gtk_sequence_node_prev (GtkSequenceNode *node);
static GtkSequenceNode *_gtk_sequence_node_next (GtkSequenceNode *node);
static gint _gtk_sequence_node_get_pos (GtkSequenceNode *node);
static GtkSequence *_gtk_sequence_node_get_sequence (GtkSequenceNode *node);
static GtkSequenceNode *_gtk_sequence_node_find_closest (GtkSequenceNode *node,
GtkSequenceNode *other,
GCompareDataFunc cmp,
gpointer data);
static gint _gtk_sequence_node_get_length (GtkSequenceNode *node);
static void _gtk_sequence_node_free (GtkSequenceNode *node,
GDestroyNotify destroy);
#if 0
static gboolean _gtk_sequence_node_is_singleton (GtkSequenceNode *node);
#endif
static void _gtk_sequence_node_split (GtkSequenceNode *node,
GtkSequenceNode **left,
GtkSequenceNode **right);
static void _gtk_sequence_node_insert_before (GtkSequenceNode *node,
GtkSequenceNode *new);
static void _gtk_sequence_node_remove (GtkSequenceNode *node);
static void _gtk_sequence_node_insert_sorted (GtkSequenceNode *node,
GtkSequenceNode *new,
GCompareDataFunc cmp_func,
gpointer cmp_data);
/* GtkSequence */
GtkSequence *
_gtk_sequence_new (GDestroyNotify data_destroy)
{
GtkSequence *seq = g_new (GtkSequence, 1);
seq->data_destroy_notify = data_destroy;
seq->node = _gtk_sequence_node_new (NULL);
seq->node->is_end = TRUE;
seq->node->sequence = seq;
return seq;
}
void
_gtk_sequence_foreach (GtkSequence *seq,
GFunc func,
gpointer data)
{
GtkSequencePtr ptr;
g_return_if_fail (seq != NULL);
g_return_if_fail (func != NULL);
ptr = _gtk_sequence_get_begin_ptr (seq);
while (!_gtk_sequence_ptr_is_end (ptr))
{
GtkSequenceNode *node = ptr;
func (node->data, data);
ptr = _gtk_sequence_ptr_next (ptr);
}
}
void
_gtk_sequence_free (GtkSequence *seq)
{
g_return_if_fail (seq != NULL);
_gtk_sequence_node_free (seq->node, seq->data_destroy_notify);
g_free (seq);
}
#if 0
static void
flatten_nodes (GtkSequenceNode *node, GList **list)
{
g_print ("flatten %p\n", node);
if (!node)
return;
else if (_gtk_sequence_node_is_singleton (node))
*list = g_list_prepend (*list, node);
else
{
GtkSequenceNode *left;
GtkSequenceNode *right;
_gtk_sequence_node_split (node, &left, &right);
flatten_nodes (left, list);
flatten_nodes (right, list);
}
}
#endif
typedef struct SortInfo SortInfo;
struct SortInfo {
GCompareDataFunc cmp;
gpointer data;
};
static gint
node_compare (gconstpointer n1, gconstpointer n2, gpointer data)
{
SortInfo *info = data;
const GtkSequenceNode *node1 = n1;
const GtkSequenceNode *node2 = n2;
if (node1->is_end)
return 1;
else if (node2->is_end)
return -1;
else
return (* info->cmp) (node1, node2, info->data);
}
void
_gtk_sequence_append (GtkSequence *seq,
gpointer data)
{
GtkSequenceNode *node, *last;
g_return_if_fail (seq != NULL);
node = _gtk_sequence_node_new (data);
node->sequence = seq;
last = _gtk_sequence_node_find_last (seq->node);
_gtk_sequence_node_insert_before (last, node);
}
#if 0
void
_gtk_sequence_prepend (GtkSequence *seq,
gpointer data)
{
GtkSequenceNode *node, *second;
g_return_if_fail (seq != NULL);
node = _gtk_sequence_node_new (data);
node->sequence = seq;
second = _gtk_sequence_node_next (_gtk_sequence_node_find_first (seq->node));
_gtk_sequence_node_insert_before (second, node);
}
#endif
GtkSequencePtr
_gtk_sequence_insert (GtkSequencePtr ptr,
gpointer data)
{
GtkSequenceNode *node;
g_return_val_if_fail (ptr != NULL, NULL);
node = _gtk_sequence_node_new (data);
node->sequence = ptr->sequence;
_gtk_sequence_node_insert_before (ptr, node);
return node;
}
static void
_gtk_sequence_unlink (GtkSequence *seq,
GtkSequenceNode *node)
{
g_assert (!node->is_end);
seq->node = _gtk_sequence_node_next (node);
g_assert (seq->node);
g_assert (seq->node != node);
_gtk_sequence_node_remove (node);
}
void
_gtk_sequence_remove (GtkSequencePtr ptr)
{
GtkSequence *seq;
g_return_if_fail (ptr != NULL);
g_return_if_fail (!ptr->is_end);
seq = _gtk_sequence_node_get_sequence (ptr);
_gtk_sequence_unlink (seq, ptr);
_gtk_sequence_node_free (ptr, seq->data_destroy_notify);
}
void
_gtk_sequence_sort (GtkSequence *seq,
GCompareDataFunc cmp_func,
gpointer cmp_data)
{
GtkSequence *tmp;
GtkSequenceNode *begin, *end;
g_return_if_fail (seq != NULL);
g_return_if_fail (cmp_func != NULL);
begin = _gtk_sequence_get_begin_ptr (seq);
end = _gtk_sequence_get_end_ptr (seq);
_gtk_sequence_remove_range (begin, end, &tmp);
while (_gtk_sequence_get_length (tmp) > 0)
{
GtkSequenceNode *node = _gtk_sequence_get_begin_ptr (tmp);
_gtk_sequence_unlink (tmp, node);
_gtk_sequence_node_insert_sorted (seq->node, node, cmp_func, cmp_data);
}
_gtk_sequence_free (tmp);
}
gpointer
_gtk_sequence_ptr_get_data (GtkSequencePtr ptr)
{
g_return_val_if_fail (ptr != NULL, NULL);
g_return_val_if_fail (!ptr->is_end, NULL);
return ptr->data;
}
GtkSequencePtr
_gtk_sequence_insert_sorted (GtkSequence *seq,
gpointer data,
GCompareDataFunc cmp_func,
gpointer cmp_data)
{
GtkSequenceNode *new_node = _gtk_sequence_node_new (data);
new_node->sequence = seq;
_gtk_sequence_node_insert_sorted (seq->node, new_node, cmp_func, cmp_data);
return new_node;
}
void
_gtk_sequence_insert_sequence (GtkSequencePtr ptr,
GtkSequence *other_seq)
{
GtkSequenceNode *last;
g_return_if_fail (other_seq != NULL);
g_return_if_fail (ptr != NULL);
last = _gtk_sequence_node_find_last (other_seq->node);
_gtk_sequence_node_insert_before (ptr, last);
_gtk_sequence_node_remove (last);
_gtk_sequence_node_free (last, NULL);
other_seq->node = NULL;
_gtk_sequence_free (other_seq);
}
void
_gtk_sequence_concatenate (GtkSequence *seq1,
GtkSequence *seq2)
{
GtkSequenceNode *last;
g_return_if_fail (seq1 != NULL);
g_return_if_fail (seq2 != NULL);
last = _gtk_sequence_node_find_last (seq1->node);
_gtk_sequence_insert_sequence (last, seq2);
}
/*
* The new sequence inherits the destroy notify from the sequence that
* beign and end comes from
*/
void
_gtk_sequence_remove_range (GtkSequencePtr begin,
GtkSequencePtr end,
GtkSequence **removed)
{
GtkSequence *seq;
GtkSequenceNode *s1, *s2, *s3;
seq = _gtk_sequence_node_get_sequence (begin);
g_assert (end != NULL);
g_return_if_fail (seq == _gtk_sequence_node_get_sequence (end));
_gtk_sequence_node_split (begin, &s1, &s2);
_gtk_sequence_node_split (end, NULL, &s3);
if (s1)
_gtk_sequence_node_insert_before (s3, s1);
seq->node = s3;
if (removed)
{
*removed = _gtk_sequence_new (seq->data_destroy_notify);
_gtk_sequence_node_insert_before ((*removed)->node, s2);
}
else
{
_gtk_sequence_node_free (s2, seq->data_destroy_notify);
}
}
gint
_gtk_sequence_get_length (GtkSequence *seq)
{
return _gtk_sequence_node_get_length (seq->node) - 1;
}
GtkSequencePtr
_gtk_sequence_get_end_ptr (GtkSequence *seq)
{
g_return_val_if_fail (seq != NULL, NULL);
return _gtk_sequence_node_find_last (seq->node);
}
GtkSequencePtr
_gtk_sequence_get_begin_ptr (GtkSequence *seq)
{
g_return_val_if_fail (seq != NULL, NULL);
return _gtk_sequence_node_find_first (seq->node);
}
/*
* if pos > number of items or -1, will return end pointer
*/
GtkSequencePtr
_gtk_sequence_get_ptr_at_pos (GtkSequence *seq,
gint pos)
{
gint len;
g_return_val_if_fail (seq != NULL, NULL);
len = _gtk_sequence_get_length (seq);
if (pos > len || pos == -1)
pos = len;
return _gtk_sequence_node_find_by_pos (seq->node, pos);
}
/* GtkSequencePtr */
gboolean
_gtk_sequence_ptr_is_end (GtkSequencePtr ptr)
{
g_return_val_if_fail (ptr != NULL, FALSE);
return ptr->is_end;
}
gboolean
_gtk_sequence_ptr_is_begin (GtkSequencePtr ptr)
{
return (_gtk_sequence_node_prev (ptr) == ptr);
}
/* If you call this on an end pointer you'll get
* the length of the sequence
*/
gint
_gtk_sequence_ptr_get_position (GtkSequencePtr ptr)
{
g_return_val_if_fail (ptr != NULL, -1);
return _gtk_sequence_node_get_pos (ptr);
}
GtkSequencePtr
_gtk_sequence_ptr_next (GtkSequencePtr ptr)
{
g_return_val_if_fail (ptr != NULL, NULL);
return _gtk_sequence_node_next (ptr);
}
GtkSequencePtr
_gtk_sequence_ptr_prev (GtkSequencePtr ptr)
{
g_return_val_if_fail (ptr != NULL, NULL);
return _gtk_sequence_node_prev (ptr);
}
GtkSequencePtr
_gtk_sequence_ptr_move (GtkSequencePtr ptr,
guint delta)
{
gint new_pos;
g_return_val_if_fail (ptr != NULL, NULL);
new_pos = _gtk_sequence_node_get_pos (ptr) + delta;
return _gtk_sequence_node_find_by_pos (ptr, new_pos);
}
void
_gtk_sequence_sort_changed (GtkSequencePtr ptr,
GCompareDataFunc cmp_func,
gpointer cmp_data)
{
GtkSequence *seq;
g_return_if_fail (!ptr->is_end);
seq = _gtk_sequence_node_get_sequence (ptr);
_gtk_sequence_unlink (seq, ptr);
_gtk_sequence_node_insert_sorted (seq->node, ptr, cmp_func, cmp_data);
}
/* search
*
* The only restriction on the search function is that it
* must not delete any nodes. It is permitted to insert new nodes,
* but the caller should "know what he is doing"
*/
void
_gtk_sequence_search (GtkSequence *seq,
GtkSequenceSearchFunc f,
gpointer data)
{
GQueue *intervals = g_queue_new ();
g_queue_push_tail (intervals, _gtk_sequence_node_find_first (seq->node));
g_queue_push_tail (intervals, _gtk_sequence_node_find_last (seq->node));
while (!g_queue_is_empty (intervals))
{
GtkSequenceNode *begin = g_queue_pop_head (intervals);
GtkSequenceNode *end = g_queue_pop_head (intervals);
if (f (begin, end, data))
{
gint begin_pos = _gtk_sequence_node_get_pos (begin);
gint end_pos = _gtk_sequence_node_get_pos (end);
if (end_pos - begin_pos > 1)
{
GtkSequenceNode *mid;
gint mid_pos;
mid_pos = begin_pos + (end_pos - begin_pos) / 2;
mid = _gtk_sequence_node_find_by_pos (begin, mid_pos);
g_queue_push_tail (intervals, begin);
g_queue_push_tail (intervals, mid);
g_queue_push_tail (intervals, mid);
g_queue_push_tail (intervals, end);
}
}
}
g_queue_free (intervals);
}
#if 0
/* aggregates */
void
_gtk_sequence_add_aggregate (GtkSequence *seq,
const gchar *aggregate,
GtkSequenceAggregateFunc f,
gpointer data,
GDestroyNotify destroy)
{
/* FIXME */
}
void
_gtk_sequence_remove_aggregate (GtkSequence *seq,
const gchar aggregate)
{
/* FIXME */
}
void
_gtk_sequence_set_aggregate_data (GtkSequencePtr ptr,
const gchar *aggregate,
gpointer data)
{
/* FIXME */
}
gpointer
_gtk_sequence_get_aggregate_data (GtkSequencePtr begin,
GtkSequencePtr end,
const gchar *aggregate)
{
g_assert_not_reached();
return NULL;
}
#endif
/* Nodes
*/
static void
_gtk_sequence_node_update_fields (GtkSequenceNode *node)
{
g_assert (node != NULL);
node->n_nodes = 1;
if (node->left)
node->n_nodes += node->left->n_nodes;
if (node->right)
node->n_nodes += node->right->n_nodes;
#if 0
if (node->left || node->right)
g_assert (node->n_nodes > 1);
#endif
}
#define NODE_LEFT_CHILD(n) (((n)->parent) && ((n)->parent->left) == (n))
#define NODE_RIGHT_CHILD(n) (((n)->parent) && ((n)->parent->right) == (n))
static void
_gtk_sequence_node_rotate (GtkSequenceNode *node)
{
GtkSequenceNode *tmp, *old;
g_assert (node->parent);
g_assert (node->parent != node);
if (NODE_LEFT_CHILD (node))
{
/* rotate right */
tmp = node->right;
node->right = node->parent;
node->parent = node->parent->parent;
if (node->parent)
{
if (node->parent->left == node->right)
node->parent->left = node;
else
node->parent->right = node;
}
g_assert (node->right);
node->right->parent = node;
node->right->left = tmp;
if (node->right->left)
node->right->left->parent = node->right;
old = node->right;
}
else
{
/* rotate left */
tmp = node->left;
node->left = node->parent;
node->parent = node->parent->parent;
if (node->parent)
{
if (node->parent->right == node->left)
node->parent->right = node;
else
node->parent->left = node;
}
g_assert (node->left);
node->left->parent = node;
node->left->right = tmp;
if (node->left->right)
node->left->right->parent = node->left;
old = node->left;
}
_gtk_sequence_node_update_fields (old);
_gtk_sequence_node_update_fields (node);
}
static GtkSequenceNode *
splay (GtkSequenceNode *node)
{
while (node->parent)
{
if (!node->parent->parent)
{
/* zig */
_gtk_sequence_node_rotate (node);
}
else if ((NODE_LEFT_CHILD (node) && NODE_LEFT_CHILD (node->parent)) ||
(NODE_RIGHT_CHILD (node) && NODE_RIGHT_CHILD (node->parent)))
{
/* zig-zig */
_gtk_sequence_node_rotate (node->parent);
_gtk_sequence_node_rotate (node);
}
else
{
/* zig-zag */
_gtk_sequence_node_rotate (node);
_gtk_sequence_node_rotate (node);
}
}
return node;
}
static GtkSequenceNode *
_gtk_sequence_node_new (gpointer data)
{
GtkSequenceNode *node = g_new0 (GtkSequenceNode, 1);
node->parent = NULL;
node->left = NULL;
node->right = NULL;
node->data = data;
node->is_end = FALSE;
node->n_nodes = 1;
return node;
}
static GtkSequenceNode *
find_min (GtkSequenceNode *node)
{
splay (node);
while (node->left)
node = node->left;
return node;
}
static GtkSequenceNode *
find_max (GtkSequenceNode *node)
{
splay (node);
while (node->right)
node = node->right;
return node;
}
static GtkSequenceNode *
_gtk_sequence_node_find_first (GtkSequenceNode *node)
{
return splay (find_min (node));
}
static GtkSequenceNode *
_gtk_sequence_node_find_last (GtkSequenceNode *node)
{
return splay (find_max (node));
}
static gint
get_n_nodes (GtkSequenceNode *node)
{
if (node)
return node->n_nodes;
else
return 0;
}
static GtkSequenceNode *
_gtk_sequence_node_find_by_pos (GtkSequenceNode *node,
gint pos)
{
gint i;
g_assert (node != NULL);
splay (node);
while ((i = get_n_nodes (node->left)) != pos)
{
if (i < pos)
{
node = node->right;
pos -= (i + 1);
}
else
{
node = node->left;
g_assert (node->parent != NULL);
}
}
return splay (node);
}
static GtkSequenceNode *
_gtk_sequence_node_prev (GtkSequenceNode *node)
{
splay (node);
if (node->left)
{
node = node->left;
while (node->right)
node = node->right;
}
return splay (node);
}
static GtkSequenceNode *
_gtk_sequence_node_next (GtkSequenceNode *node)
{
splay (node);
if (node->right)
{
node = node->right;
while (node->left)
node = node->left;
}
return splay (node);
}
static gint
_gtk_sequence_node_get_pos (GtkSequenceNode *node)
{
splay (node);
return get_n_nodes (node->left);
}
static GtkSequence *
_gtk_sequence_node_get_sequence (GtkSequenceNode *node)
{
splay (node);
return node->sequence;
}
static GtkSequenceNode *
_gtk_sequence_node_find_closest (GtkSequenceNode *node,
GtkSequenceNode *other,
GCompareDataFunc cmp,
gpointer data)
{
GtkSequenceNode *best;
gint c;
splay (node);
do
{
best = node;
if ((c = cmp (node, other, data)) != 0)
{
if (c < 0)
node = node->right;
else
node = node->left;
}
}
while (c != 0 && node != NULL);
return best;
}
static void
_gtk_sequence_node_free (GtkSequenceNode *node,
GDestroyNotify destroy)
{
/* FIXME:
*
* This is to avoid excessively deep recursions. A splay tree is not necessarily
* balanced at all.
*
* I _think_ this is still linear in the number of nodes, but I'd like to
* do something more efficient.
*/
while (node)
{
GtkSequenceNode *next;
node = splay (find_min (node));
next = node->right;
if (next)
next->parent = NULL;
if (destroy && !node->is_end)
destroy (node->data);
g_free (node);
node = next;
}
}
#if 0
static gboolean
_gtk_sequence_node_is_singleton (GtkSequenceNode *node)
{
splay (node);
if (node->left || node->right)
return FALSE;
return TRUE;
}
#endif
static void
_gtk_sequence_node_split (GtkSequenceNode *node,
GtkSequenceNode **left,
GtkSequenceNode **right)
{
GtkSequenceNode *left_tree;
splay (node);
left_tree = node->left;
if (left_tree)
{
left_tree->parent = NULL;
_gtk_sequence_node_update_fields (left_tree);
}
node->left = NULL;
_gtk_sequence_node_update_fields (node);
if (left)
*left = left_tree;
if (right)
*right = node;
}
static void
_gtk_sequence_node_insert_before (GtkSequenceNode *node,
GtkSequenceNode *new)
{
g_assert (node != NULL);
g_assert (new != NULL);
splay (node);
new = splay (find_min (new));
g_assert (new->left == NULL);
if (node->left)
node->left->parent = new;
new->left = node->left;
new->parent = node;
node->left = new;
_gtk_sequence_node_update_fields (new);
_gtk_sequence_node_update_fields (node);
}
static gint
_gtk_sequence_node_get_length (GtkSequenceNode *node)
{
g_assert (node != NULL);
splay (node);
return node->n_nodes;
}
static void
_gtk_sequence_node_remove (GtkSequenceNode *node)
{
GtkSequenceNode *right, *left;
splay (node);
left = node->left;
right = node->right;
node->left = node->right = NULL;
if (right)
{
right->parent = NULL;
right = _gtk_sequence_node_find_first (right);
g_assert (right->left == NULL);
right->left = left;
if (left)
{
left->parent = right;
_gtk_sequence_node_update_fields (right);
}
}
else if (left)
left->parent = NULL;
}
#if 0
/* debug func */
static gint
_gtk_sequence_node_calc_height (GtkSequenceNode *node)
{
/* breadth first traversal */
gint height = 0;
GQueue *nodes = g_queue_new ();
g_queue_push_tail (nodes, node);
while (!g_queue_is_empty (nodes))
{
GQueue *tmp = g_queue_new ();
height++;
while (!g_queue_is_empty (nodes))
{
GtkSequenceNode *node = g_queue_pop_head (nodes);
if (node->left)
g_queue_push_tail (tmp, node->left);
if (node->right)
g_queue_push_tail (tmp, node->right);
}
g_queue_free (nodes);
nodes = tmp;
}
g_queue_free (nodes);
return height;
}
#endif
static void
_gtk_sequence_node_insert_sorted (GtkSequenceNode *node,
GtkSequenceNode *new,
GCompareDataFunc cmp_func,
gpointer cmp_data)
{
SortInfo info;
GtkSequenceNode *closest;
info.cmp = cmp_func;
info.data = cmp_data;
closest =
_gtk_sequence_node_find_closest (node, new, node_compare, &info);
g_assert (closest != new);
if (node_compare (new, closest, &info) > 0)
closest = _gtk_sequence_node_next (closest);
/* this can never fail since we have a bigger-than-everything
* end-node
*/
g_assert (node_compare (new, closest, &info) <= 0);
_gtk_sequence_node_insert_before (closest, new);
}
static gint
_gtk_sequence_node_calc_height (GtkSequenceNode *node)
{
gint left_height;
gint right_height;
if (node)
{
left_height = 0;
right_height = 0;
if (node->left)
left_height = _gtk_sequence_node_calc_height (node->left);
if (node->right)
right_height = _gtk_sequence_node_calc_height (node->right);
return MAX (left_height, right_height) + 1;
}
return 0;
}
gint
_gtk_sequence_calc_tree_height (GtkSequence *seq)
{
GtkSequenceNode *node = seq->node;
gint r, l;
while (node->parent)
node = node->parent;
if (node)
{
r = _gtk_sequence_node_calc_height (node->right);
l = _gtk_sequence_node_calc_height (node->left);
return MAX (r, l) + 1;
}
else
return 0;
}
GtkSequence *
_gtk_sequence_ptr_get_sequence (GtkSequencePtr ptr)
{
GtkSequenceNode *node = ptr;
return node->sequence;
}
void
_gtk_sequence_swap (GtkSequencePtr a,
GtkSequencePtr b)
{
GtkSequenceNode *leftmost, *rightmost, *rightmost_next;
int a_pos, b_pos;
g_return_if_fail (!_gtk_sequence_ptr_is_end (a));
g_return_if_fail (!_gtk_sequence_ptr_is_end (b));
if (a == b)
return;
a_pos = _gtk_sequence_ptr_get_position (a);
b_pos = _gtk_sequence_ptr_get_position (b);
if (a_pos > b_pos)
{
leftmost = b;
rightmost = a;
}
else
{
leftmost = a;
rightmost = b;
}
rightmost_next = _gtk_sequence_node_next (rightmost);
/* Situation now: ..., leftmost, ......., rightmost, rightmost_next, ... */
_gtk_sequence_move (rightmost, leftmost);
_gtk_sequence_move (leftmost, rightmost_next);
}
void
_gtk_sequence_move (GtkSequencePtr ptr,
GtkSequencePtr new_pos)
{
g_return_if_fail (ptr != NULL);
g_return_if_fail (new_pos != NULL);
if (ptr == new_pos)
return;
_gtk_sequence_unlink (ptr->sequence, ptr);
_gtk_sequence_node_insert_before (new_pos, ptr);
}
/* Overwrites the existing pointer. */
void
_gtk_sequence_set (GtkSequencePtr ptr,
gpointer data)
{
GtkSequence *seq;
g_return_if_fail (!_gtk_sequence_ptr_is_end (ptr));
seq = _gtk_sequence_node_get_sequence (ptr);
if (seq->data_destroy_notify)
seq->data_destroy_notify (ptr->data);
ptr->data = data;
}