Blame gtk/gtktextbtree.c

Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Gtktextbtree.c --
Packit Service fb6fa5
 *
Packit Service fb6fa5
 *      This file contains code that manages the B-tree representation
Packit Service fb6fa5
 *      of text for the text buffer and implements character and
Packit Service fb6fa5
 *      toggle segment types.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * Copyright (c) 1992-1994 The Regents of the University of California.
Packit Service fb6fa5
 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
Packit Service fb6fa5
 * Copyright (c) 2000      Red Hat, Inc.
Packit Service fb6fa5
 * Tk -> Gtk port by Havoc Pennington <hp@redhat.com>
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This software is copyrighted by the Regents of the University of
Packit Service fb6fa5
 * California, Sun Microsystems, Inc., and other parties.  The
Packit Service fb6fa5
 * following terms apply to all files associated with the software
Packit Service fb6fa5
 * unless explicitly disclaimed in individual files.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * The authors hereby grant permission to use, copy, modify,
Packit Service fb6fa5
 * distribute, and license this software and its documentation for any
Packit Service fb6fa5
 * purpose, provided that existing copyright notices are retained in
Packit Service fb6fa5
 * all copies and that this notice is included verbatim in any
Packit Service fb6fa5
 * distributions. No written agreement, license, or royalty fee is
Packit Service fb6fa5
 * required for any of the authorized uses.  Modifications to this
Packit Service fb6fa5
 * software may be copyrighted by their authors and need not follow
Packit Service fb6fa5
 * the licensing terms described here, provided that the new terms are
Packit Service fb6fa5
 * clearly indicated on the first page of each file where they apply.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
Packit Service fb6fa5
 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
Packit Service fb6fa5
 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
Packit Service fb6fa5
 * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
Packit Service fb6fa5
 * OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
Packit Service fb6fa5
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
Packit Service fb6fa5
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
Packit Service fb6fa5
 * NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
Packit Service fb6fa5
 * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
Packit Service fb6fa5
 * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * GOVERNMENT USE: If you are acquiring this software on behalf of the
Packit Service fb6fa5
 * U.S. government, the Government shall have only "Restricted Rights"
Packit Service fb6fa5
 * in the software and related documentation as defined in the Federal
Packit Service fb6fa5
 * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
Packit Service fb6fa5
 * are acquiring the software on behalf of the Department of Defense,
Packit Service fb6fa5
 * the software shall be classified as "Commercial Computer Software"
Packit Service fb6fa5
 * and the Government shall have only "Restricted Rights" as defined
Packit Service fb6fa5
 * in Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
Packit Service fb6fa5
 * foregoing, the authors grant the U.S. Government and others acting
Packit Service fb6fa5
 * in its behalf permission to use and distribute the software in
Packit Service fb6fa5
 * accordance with the terms specified in this license.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
Packit Service fb6fa5
#include "config.h"
Packit Service fb6fa5
#include "gtktextbtree.h"
Packit Service fb6fa5
#include <string.h>
Packit Service fb6fa5
#include <stdlib.h>
Packit Service fb6fa5
#include <stdio.h>
Packit Service fb6fa5
#include "gtktexttag.h"
Packit Service fb6fa5
#include "gtktexttagtable.h"
Packit Service fb6fa5
#include "gtktextlayout.h"
Packit Service fb6fa5
#include "gtktextiterprivate.h"
Packit Service fb6fa5
#include "gtkdebug.h"
Packit Service fb6fa5
#include "gtktextmarkprivate.h"
Packit Service fb6fa5
#include "gtkalias.h"
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Types
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * The structure below is used to pass information between
Packit Service fb6fa5
 * _gtk_text_btree_get_tags and inc_count:
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct TagInfo {
Packit Service fb6fa5
  int numTags;                  /* Number of tags for which there
Packit Service fb6fa5
                                 * is currently information in
Packit Service fb6fa5
                                 * tags and counts. */
Packit Service fb6fa5
  int arraySize;                        /* Number of entries allocated for
Packit Service fb6fa5
                                         * tags and counts. */
Packit Service fb6fa5
  GtkTextTag **tags;           /* Array of tags seen so far.
Packit Service fb6fa5
                                * Malloc-ed. */
Packit Service fb6fa5
  int *counts;                  /* Toggle count (so far) for each
Packit Service fb6fa5
                                 * entry in tags.  Malloc-ed. */
Packit Service fb6fa5
} TagInfo;
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * This is used to store per-view width/height info at the tree nodes.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct _NodeData NodeData;
Packit Service fb6fa5
Packit Service fb6fa5
struct _NodeData {
Packit Service fb6fa5
  gpointer view_id;
Packit Service fb6fa5
  NodeData *next;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Height and width of this node */
Packit Service fb6fa5
  gint height;
Packit Service fb6fa5
  signed int width : 24;
Packit Service fb6fa5
Packit Service fb6fa5
  /* boolean indicating whether the lines below this node are in need of validation.
Packit Service fb6fa5
   * However, width/height should always represent the current total width and
Packit Service fb6fa5
   * max height for lines below this node; the valid flag indicates whether the
Packit Service fb6fa5
   * width/height on the lines needs recomputing, not whether the totals
Packit Service fb6fa5
   * need recomputing.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  guint valid : 8;		/* Actually a boolean */
Packit Service fb6fa5
};
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * The data structure below keeps summary information about one tag as part
Packit Service fb6fa5
 * of the tag information in a node.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct Summary {
Packit Service fb6fa5
  GtkTextTagInfo *info;                     /* Handle for tag. */
Packit Service fb6fa5
  int toggle_count;                     /* Number of transitions into or
Packit Service fb6fa5
                                         * out of this tag that occur in
Packit Service fb6fa5
                                         * the subtree rooted at this node. */
Packit Service fb6fa5
  struct Summary *next;         /* Next in list of all tags for same
Packit Service fb6fa5
                                 * node, or NULL if at end of list. */
Packit Service fb6fa5
} Summary;
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * The data structure below defines a node in the B-tree.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
struct _GtkTextBTreeNode {
Packit Service fb6fa5
  GtkTextBTreeNode *parent;         /* Pointer to parent node, or NULL if
Packit Service fb6fa5
                                     * this is the root. */
Packit Service fb6fa5
  GtkTextBTreeNode *next;           /* Next in list of siblings with the
Packit Service fb6fa5
                                     * same parent node, or NULL for end
Packit Service fb6fa5
                                     * of list. */
Packit Service fb6fa5
  Summary *summary;             /* First in malloc-ed list of info
Packit Service fb6fa5
                                 * about tags in this subtree (NULL if
Packit Service fb6fa5
                                 * no tag info in the subtree). */
Packit Service fb6fa5
  int level;                            /* Level of this node in the B-tree.
Packit Service fb6fa5
                                         * 0 refers to the bottom of the tree
Packit Service fb6fa5
                                         * (children are lines, not nodes). */
Packit Service fb6fa5
  union {                               /* First in linked list of children. */
Packit Service fb6fa5
    struct _GtkTextBTreeNode *node;         /* Used if level > 0. */
Packit Service fb6fa5
    GtkTextLine *line;         /* Used if level == 0. */
Packit Service fb6fa5
  } children;
Packit Service fb6fa5
  int num_children;                     /* Number of children of this node. */
Packit Service fb6fa5
  int num_lines;                        /* Total number of lines (leaves) in
Packit Service fb6fa5
                                         * the subtree rooted here. */
Packit Service fb6fa5
  int num_chars;                        /* Number of chars below here */
Packit Service fb6fa5
Packit Service fb6fa5
  NodeData *node_data;
Packit Service fb6fa5
};
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Used to store the list of views in our btree
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct _BTreeView BTreeView;
Packit Service fb6fa5
Packit Service fb6fa5
struct _BTreeView {
Packit Service fb6fa5
  gpointer view_id;
Packit Service fb6fa5
  GtkTextLayout *layout;
Packit Service fb6fa5
  BTreeView *next;
Packit Service fb6fa5
  BTreeView *prev;
Packit Service fb6fa5
};
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * And the tree itself
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
struct _GtkTextBTree {
Packit Service fb6fa5
  GtkTextBTreeNode *root_node;          /* Pointer to root of B-tree. */
Packit Service fb6fa5
  GtkTextTagTable *table;
Packit Service fb6fa5
  GHashTable *mark_table;
Packit Service fb6fa5
  guint refcount;
Packit Service fb6fa5
  GtkTextMark *insert_mark;
Packit Service fb6fa5
  GtkTextMark *selection_bound_mark;
Packit Service fb6fa5
  GtkTextBuffer *buffer;
Packit Service fb6fa5
  BTreeView *views;
Packit Service fb6fa5
  GSList *tag_infos;
Packit Service fb6fa5
  gulong tag_changed_handler;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Incremented when a segment with a byte size > 0
Packit Service fb6fa5
   * is added to or removed from the tree (i.e. the
Packit Service fb6fa5
   * length of a line may have changed, and lines may
Packit Service fb6fa5
   * have been added or removed). This invalidates
Packit Service fb6fa5
   * all outstanding iterators.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  guint chars_changed_stamp;
Packit Service fb6fa5
  /* Incremented when any segments are added or deleted;
Packit Service fb6fa5
   * this makes outstanding iterators recalculate their
Packit Service fb6fa5
   * pointed-to segment and segment offset.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  guint segments_changed_stamp;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Cache the last line in the buffer */
Packit Service fb6fa5
  GtkTextLine *last_line;
Packit Service fb6fa5
  guint last_line_stamp;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Cache the next-to-last line in the buffer,
Packit Service fb6fa5
   * containing the end iterator
Packit Service fb6fa5
   */
Packit Service fb6fa5
  GtkTextLine *end_iter_line;
Packit Service fb6fa5
  GtkTextLineSegment *end_iter_segment;
Packit Service fb6fa5
  int end_iter_segment_byte_index;
Packit Service fb6fa5
  int end_iter_segment_char_offset;
Packit Service fb6fa5
  guint end_iter_line_stamp;
Packit Service fb6fa5
  guint end_iter_segment_stamp;
Packit Service fb6fa5
  
Packit Service fb6fa5
  GHashTable *child_anchor_table;
Packit Service fb6fa5
};
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Upper and lower bounds on how many children a node may have:
Packit Service fb6fa5
 * rebalance when either of these limits is exceeded.  MAX_CHILDREN
Packit Service fb6fa5
 * should be twice MIN_CHILDREN and MIN_CHILDREN must be >= 2.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
/* Tk used MAX of 12 and MIN of 6. This makes the tree wide and
Packit Service fb6fa5
   shallow. It appears to be faster to locate a particular line number
Packit Service fb6fa5
   if the tree is narrow and deep, since it is more finely sorted.  I
Packit Service fb6fa5
   guess this may increase memory use though, and make it slower to
Packit Service fb6fa5
   walk the tree in order, or locate a particular byte index (which
Packit Service fb6fa5
   is done by walking the tree in order).
Packit Service fb6fa5
Packit Service fb6fa5
   There's basically a tradeoff here. However I'm thinking we want to
Packit Service fb6fa5
   add pixels, byte counts, and char counts to the tree nodes,
Packit Service fb6fa5
   at that point narrow and deep should speed up all operations,
Packit Service fb6fa5
   not just the line number searches.
Packit Service fb6fa5
*/
Packit Service fb6fa5
Packit Service fb6fa5
#if 1
Packit Service fb6fa5
#define MAX_CHILDREN 12
Packit Service fb6fa5
#define MIN_CHILDREN 6
Packit Service fb6fa5
#else
Packit Service fb6fa5
#define MAX_CHILDREN 6
Packit Service fb6fa5
#define MIN_CHILDREN 3
Packit Service fb6fa5
#endif
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Prototypes
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
static BTreeView        *gtk_text_btree_get_view                 (GtkTextBTree     *tree,
Packit Service fb6fa5
                                                                  gpointer          view_id);
Packit Service fb6fa5
static void              gtk_text_btree_rebalance                (GtkTextBTree     *tree,
Packit Service fb6fa5
                                                                  GtkTextBTreeNode *node);
Packit Service fb6fa5
static GtkTextLine     * get_last_line                           (GtkTextBTree     *tree);
Packit Service fb6fa5
static void              post_insert_fixup                       (GtkTextBTree     *tree,
Packit Service fb6fa5
                                                                  GtkTextLine      *insert_line,
Packit Service fb6fa5
                                                                  gint              char_count_delta,
Packit Service fb6fa5
                                                                  gint              line_count_delta);
Packit Service fb6fa5
static void              gtk_text_btree_node_adjust_toggle_count (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                  GtkTextTagInfo   *info,
Packit Service fb6fa5
                                                                  gint              adjust);
Packit Service fb6fa5
static gboolean          gtk_text_btree_node_has_tag             (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                  GtkTextTag       *tag);
Packit Service fb6fa5
Packit Service fb6fa5
static void             segments_changed                (GtkTextBTree     *tree);
Packit Service fb6fa5
static void             chars_changed                   (GtkTextBTree     *tree);
Packit Service fb6fa5
static void             summary_list_destroy            (Summary          *summary);
Packit Service fb6fa5
static GtkTextLine     *gtk_text_line_new               (void);
Packit Service fb6fa5
static void             gtk_text_line_destroy           (GtkTextBTree     *tree,
Packit Service fb6fa5
                                                         GtkTextLine      *line);
Packit Service fb6fa5
static void             gtk_text_line_set_parent        (GtkTextLine      *line,
Packit Service fb6fa5
                                                         GtkTextBTreeNode *node);
Packit Service fb6fa5
static void             gtk_text_btree_node_remove_data (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                         gpointer          view_id);
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static NodeData         *node_data_new          (gpointer  view_id);
Packit Service fb6fa5
static void              node_data_destroy      (NodeData *nd);
Packit Service fb6fa5
static void              node_data_list_destroy (NodeData *nd);
Packit Service fb6fa5
static NodeData         *node_data_find         (NodeData *nd,
Packit Service fb6fa5
                                                 gpointer  view_id);
Packit Service fb6fa5
Packit Service fb6fa5
static GtkTextBTreeNode     *gtk_text_btree_node_new                  (void);
Packit Service fb6fa5
#if 0
Packit Service fb6fa5
static void                  gtk_text_btree_node_invalidate_downward  (GtkTextBTreeNode *node);
Packit Service fb6fa5
#endif
Packit Service fb6fa5
static void                  gtk_text_btree_node_invalidate_upward    (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                       gpointer          view_id);
Packit Service fb6fa5
static NodeData *            gtk_text_btree_node_check_valid          (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                       gpointer          view_id);
Packit Service fb6fa5
static NodeData *            gtk_text_btree_node_check_valid_downward (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                       gpointer          view_id);
Packit Service fb6fa5
static void                  gtk_text_btree_node_check_valid_upward   (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                       gpointer          view_id);
Packit Service fb6fa5
Packit Service fb6fa5
static void                  gtk_text_btree_node_remove_view         (BTreeView        *view,
Packit Service fb6fa5
                                                                      GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                      gpointer          view_id);
Packit Service fb6fa5
static void                  gtk_text_btree_node_destroy             (GtkTextBTree     *tree,
Packit Service fb6fa5
                                                                      GtkTextBTreeNode *node);
Packit Service fb6fa5
static void                  gtk_text_btree_node_free_empty          (GtkTextBTree *tree,
Packit Service fb6fa5
                                                                      GtkTextBTreeNode *node);
Packit Service fb6fa5
static NodeData         *    gtk_text_btree_node_ensure_data         (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                      gpointer          view_id);
Packit Service fb6fa5
static void                  gtk_text_btree_node_remove_data         (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                      gpointer          view_id);
Packit Service fb6fa5
static void                  gtk_text_btree_node_get_size            (GtkTextBTreeNode *node,
Packit Service fb6fa5
                                                                      gpointer          view_id,
Packit Service fb6fa5
                                                                      gint             *width,
Packit Service fb6fa5
                                                                      gint             *height);
Packit Service fb6fa5
static GtkTextBTreeNode *    gtk_text_btree_node_common_parent       (GtkTextBTreeNode *node1,
Packit Service fb6fa5
                                                                      GtkTextBTreeNode *node2);
Packit Service fb6fa5
static void get_tree_bounds       (GtkTextBTree     *tree,
Packit Service fb6fa5
                                   GtkTextIter      *start,
Packit Service fb6fa5
                                   GtkTextIter      *end);
Packit Service fb6fa5
static void tag_changed_cb        (GtkTextTagTable  *table,
Packit Service fb6fa5
                                   GtkTextTag       *tag,
Packit Service fb6fa5
                                   gboolean          size_changed,
Packit Service fb6fa5
                                   GtkTextBTree     *tree);
Packit Service fb6fa5
static void cleanup_line          (GtkTextLine      *line);
Packit Service fb6fa5
static void recompute_node_counts (GtkTextBTree     *tree,
Packit Service fb6fa5
                                   GtkTextBTreeNode *node);
Packit Service fb6fa5
static void inc_count             (GtkTextTag       *tag,
Packit Service fb6fa5
                                   int               inc,
Packit Service fb6fa5
                                   TagInfo          *tagInfoPtr);
Packit Service fb6fa5
Packit Service fb6fa5
static void summary_destroy       (Summary          *summary);
Packit Service fb6fa5
Packit Service fb6fa5
static void gtk_text_btree_link_segment   (GtkTextLineSegment *seg,
Packit Service fb6fa5
                                           const GtkTextIter  *iter);
Packit Service fb6fa5
static void gtk_text_btree_unlink_segment (GtkTextBTree       *tree,
Packit Service fb6fa5
                                           GtkTextLineSegment *seg,
Packit Service fb6fa5
                                           GtkTextLine        *line);
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static GtkTextTagInfo *gtk_text_btree_get_tag_info          (GtkTextBTree   *tree,
Packit Service fb6fa5
                                                             GtkTextTag     *tag);
Packit Service fb6fa5
static GtkTextTagInfo *gtk_text_btree_get_existing_tag_info (GtkTextBTree   *tree,
Packit Service fb6fa5
                                                             GtkTextTag     *tag);
Packit Service fb6fa5
static void            gtk_text_btree_remove_tag_info       (GtkTextBTree   *tree,
Packit Service fb6fa5
                                                             GtkTextTag     *tag);
Packit Service fb6fa5
Packit Service fb6fa5
static void redisplay_region (GtkTextBTree      *tree,
Packit Service fb6fa5
                              const GtkTextIter *start,
Packit Service fb6fa5
                              const GtkTextIter *end,
Packit Service fb6fa5
                              gboolean           cursors_only);
Packit Service fb6fa5
Packit Service fb6fa5
/* Inline thingies */
Packit Service fb6fa5
Packit Service fb6fa5
static inline void
Packit Service fb6fa5
segments_changed (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  tree->segments_changed_stamp += 1;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static inline void
Packit Service fb6fa5
chars_changed (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  tree->chars_changed_stamp += 1;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * BTree operations
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextBTree*
Packit Service fb6fa5
_gtk_text_btree_new (GtkTextTagTable *table,
Packit Service fb6fa5
                     GtkTextBuffer *buffer)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBTree *tree;
Packit Service fb6fa5
  GtkTextBTreeNode *root_node;
Packit Service fb6fa5
  GtkTextLine *line, *line2;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (GTK_IS_TEXT_TAG_TABLE (table), NULL);
Packit Service fb6fa5
  g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * The tree will initially have two empty lines.  The second line
Packit Service fb6fa5
   * isn't actually part of the tree's contents, but its presence
Packit Service fb6fa5
   * makes several operations easier.  The tree will have one GtkTextBTreeNode,
Packit Service fb6fa5
   * which is also the root of the tree.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  /* Create the root node. */
Packit Service fb6fa5
Packit Service fb6fa5
  root_node = gtk_text_btree_node_new ();
Packit Service fb6fa5
Packit Service fb6fa5
  line = gtk_text_line_new ();
Packit Service fb6fa5
  line2 = gtk_text_line_new ();
Packit Service fb6fa5
Packit Service fb6fa5
  root_node->parent = NULL;
Packit Service fb6fa5
  root_node->next = NULL;
Packit Service fb6fa5
  root_node->summary = NULL;
Packit Service fb6fa5
  root_node->level = 0;
Packit Service fb6fa5
  root_node->children.line = line;
Packit Service fb6fa5
  root_node->num_children = 2;
Packit Service fb6fa5
  root_node->num_lines = 2;
Packit Service fb6fa5
  root_node->num_chars = 2;
Packit Service fb6fa5
Packit Service fb6fa5
  line->parent = root_node;
Packit Service fb6fa5
  line->next = line2;
Packit Service fb6fa5
Packit Service fb6fa5
  line->segments = _gtk_char_segment_new ("\n", 1);
Packit Service fb6fa5
Packit Service fb6fa5
  line2->parent = root_node;
Packit Service fb6fa5
  line2->next = NULL;
Packit Service fb6fa5
  line2->segments = _gtk_char_segment_new ("\n", 1);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Create the tree itself */
Packit Service fb6fa5
Packit Service fb6fa5
  tree = g_new0(GtkTextBTree, 1);
Packit Service fb6fa5
  tree->root_node = root_node;
Packit Service fb6fa5
  tree->table = table;
Packit Service fb6fa5
  tree->views = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Set these to values that are unlikely to be found
Packit Service fb6fa5
   * in random memory garbage, and also avoid
Packit Service fb6fa5
   * duplicates between tree instances.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  tree->chars_changed_stamp = g_random_int ();
Packit Service fb6fa5
  tree->segments_changed_stamp = g_random_int ();
Packit Service fb6fa5
Packit Service fb6fa5
  tree->last_line_stamp = tree->chars_changed_stamp - 1;
Packit Service fb6fa5
  tree->last_line = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  tree->end_iter_line_stamp = tree->chars_changed_stamp - 1;
Packit Service fb6fa5
  tree->end_iter_segment_stamp = tree->segments_changed_stamp - 1;
Packit Service fb6fa5
  tree->end_iter_line = NULL;
Packit Service fb6fa5
  tree->end_iter_segment_byte_index = 0;
Packit Service fb6fa5
  tree->end_iter_segment_char_offset = 0;
Packit Service fb6fa5
  
Packit Service fb6fa5
  g_object_ref (tree->table);
Packit Service fb6fa5
Packit Service fb6fa5
  tree->tag_changed_handler = g_signal_connect (tree->table,
Packit Service fb6fa5
						"tag-changed",
Packit Service fb6fa5
						G_CALLBACK (tag_changed_cb),
Packit Service fb6fa5
						tree);
Packit Service fb6fa5
Packit Service fb6fa5
  tree->mark_table = g_hash_table_new (g_str_hash, g_str_equal);
Packit Service fb6fa5
  tree->child_anchor_table = NULL;
Packit Service fb6fa5
  
Packit Service fb6fa5
  /* We don't ref the buffer, since the buffer owns us;
Packit Service fb6fa5
   * we'd have some circularity issues. The buffer always
Packit Service fb6fa5
   * lasts longer than the BTree
Packit Service fb6fa5
   */
Packit Service fb6fa5
  tree->buffer = buffer;
Packit Service fb6fa5
Packit Service fb6fa5
  {
Packit Service fb6fa5
    GtkTextIter start;
Packit Service fb6fa5
    GtkTextLineSegment *seg;
Packit Service fb6fa5
Packit Service fb6fa5
    _gtk_text_btree_get_iter_at_line_char (tree, &start, 0, 0);
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
    tree->insert_mark = _gtk_text_btree_set_mark (tree,
Packit Service fb6fa5
                                                 NULL,
Packit Service fb6fa5
                                                 "insert",
Packit Service fb6fa5
                                                 FALSE,
Packit Service fb6fa5
                                                 &start,
Packit Service fb6fa5
                                                 FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
    seg = tree->insert_mark->segment;
Packit Service fb6fa5
Packit Service fb6fa5
    seg->body.mark.not_deleteable = TRUE;
Packit Service fb6fa5
    seg->body.mark.visible = TRUE;
Packit Service fb6fa5
Packit Service fb6fa5
    tree->selection_bound_mark = _gtk_text_btree_set_mark (tree,
Packit Service fb6fa5
                                                          NULL,
Packit Service fb6fa5
                                                          "selection_bound",
Packit Service fb6fa5
                                                          FALSE,
Packit Service fb6fa5
                                                          &start,
Packit Service fb6fa5
                                                          FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
    seg = tree->selection_bound_mark->segment;
Packit Service fb6fa5
Packit Service fb6fa5
    seg->body.mark.not_deleteable = TRUE;
Packit Service fb6fa5
Packit Service fb6fa5
    g_object_ref (tree->insert_mark);
Packit Service fb6fa5
    g_object_ref (tree->selection_bound_mark);
Packit Service fb6fa5
  }
Packit Service fb6fa5
Packit Service fb6fa5
  tree->refcount = 1;
Packit Service fb6fa5
Packit Service fb6fa5
  return tree;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_ref (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_return_if_fail (tree != NULL);
Packit Service fb6fa5
  g_return_if_fail (tree->refcount > 0);
Packit Service fb6fa5
Packit Service fb6fa5
  tree->refcount += 1;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_unref (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_return_if_fail (tree != NULL);
Packit Service fb6fa5
  g_return_if_fail (tree->refcount > 0);
Packit Service fb6fa5
Packit Service fb6fa5
  tree->refcount -= 1;
Packit Service fb6fa5
Packit Service fb6fa5
  if (tree->refcount == 0)
Packit Service fb6fa5
    {      
Packit Service fb6fa5
      g_signal_handler_disconnect (tree->table,
Packit Service fb6fa5
                                   tree->tag_changed_handler);
Packit Service fb6fa5
Packit Service fb6fa5
      g_object_unref (tree->table);
Packit Service fb6fa5
      tree->table = NULL;
Packit Service fb6fa5
      
Packit Service fb6fa5
      gtk_text_btree_node_destroy (tree, tree->root_node);
Packit Service fb6fa5
      tree->root_node = NULL;
Packit Service fb6fa5
      
Packit Service fb6fa5
      g_assert (g_hash_table_size (tree->mark_table) == 0);
Packit Service fb6fa5
      g_hash_table_destroy (tree->mark_table);
Packit Service fb6fa5
      tree->mark_table = NULL;
Packit Service fb6fa5
      if (tree->child_anchor_table != NULL) 
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_hash_table_destroy (tree->child_anchor_table);
Packit Service fb6fa5
	  tree->child_anchor_table = NULL;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      g_object_unref (tree->insert_mark);
Packit Service fb6fa5
      tree->insert_mark = NULL;
Packit Service fb6fa5
      g_object_unref (tree->selection_bound_mark);
Packit Service fb6fa5
      tree->selection_bound_mark = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
      g_free (tree);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextBuffer*
Packit Service fb6fa5
_gtk_text_btree_get_buffer (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return tree->buffer;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
guint
Packit Service fb6fa5
_gtk_text_btree_get_chars_changed_stamp (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return tree->chars_changed_stamp;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
guint
Packit Service fb6fa5
_gtk_text_btree_get_segments_changed_stamp (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return tree->segments_changed_stamp;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_segments_changed (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_return_if_fail (tree != NULL);
Packit Service fb6fa5
  segments_changed (tree);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Indexable segment mutation
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 *  The following function is responsible for resolving the bidi direction
Packit Service fb6fa5
 *  for the lines between start and end. But it also calculates any
Packit Service fb6fa5
 *  dependent bidi direction for surrounding lines that change as a result
Packit Service fb6fa5
 *  of the bidi direction decisions within the range. The function is
Packit Service fb6fa5
 *  trying to do as little propagation as is needed.
Packit Service fb6fa5
 */
Packit Service fb6fa5
static void
Packit Service fb6fa5
gtk_text_btree_resolve_bidi (GtkTextIter *start,
Packit Service fb6fa5
			     GtkTextIter *end)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBTree *tree = _gtk_text_iter_get_btree (start);
Packit Service fb6fa5
  GtkTextLine *start_line, *end_line, *start_line_prev, *end_line_next, *line;
Packit Service fb6fa5
  PangoDirection last_strong, dir_above_propagated, dir_below_propagated;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Resolve the strong bidi direction for all lines between
Packit Service fb6fa5
   * start and end.
Packit Service fb6fa5
  */
Packit Service fb6fa5
  start_line = _gtk_text_iter_get_text_line (start);
Packit Service fb6fa5
  start_line_prev = _gtk_text_line_previous (start_line);
Packit Service fb6fa5
  end_line = _gtk_text_iter_get_text_line (end);
Packit Service fb6fa5
  end_line_next = _gtk_text_line_next (end_line);
Packit Service fb6fa5
  
Packit Service fb6fa5
  line = start_line;
Packit Service fb6fa5
  while (line && line != end_line_next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* Loop through the segments and search for a strong character
Packit Service fb6fa5
       */
Packit Service fb6fa5
      GtkTextLineSegment *seg = line->segments;
Packit Service fb6fa5
      line->dir_strong = PANGO_DIRECTION_NEUTRAL;
Packit Service fb6fa5
      
Packit Service fb6fa5
      while (seg)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          if (seg->type == &gtk_text_char_type && seg->byte_count > 0)
Packit Service fb6fa5
            {
Packit Service fb6fa5
	      PangoDirection pango_dir;
Packit Service fb6fa5
Packit Service fb6fa5
              pango_dir = pango_find_base_dir (seg->body.chars,
Packit Service fb6fa5
					       seg->byte_count);
Packit Service fb6fa5
	      
Packit Service fb6fa5
              if (pango_dir != PANGO_DIRECTION_NEUTRAL)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  line->dir_strong = pango_dir;
Packit Service fb6fa5
                  break;
Packit Service fb6fa5
                }
Packit Service fb6fa5
            }
Packit Service fb6fa5
          seg = seg->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      line = _gtk_text_line_next (line);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* Sweep forward */
Packit Service fb6fa5
Packit Service fb6fa5
  /* The variable dir_above_propagated contains the forward propagated
Packit Service fb6fa5
   * direction before start. It is neutral if start is in the beginning
Packit Service fb6fa5
   * of the buffer.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  dir_above_propagated = PANGO_DIRECTION_NEUTRAL;
Packit Service fb6fa5
  if (start_line_prev)
Packit Service fb6fa5
    dir_above_propagated = start_line_prev->dir_propagated_forward;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Loop forward and propagate the direction of each paragraph 
Packit Service fb6fa5
   * to all neutral lines.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  line = start_line;
Packit Service fb6fa5
  last_strong = dir_above_propagated;
Packit Service fb6fa5
  while (line != end_line_next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
Packit Service fb6fa5
        last_strong = line->dir_strong;
Packit Service fb6fa5
      
Packit Service fb6fa5
      line->dir_propagated_forward = last_strong;
Packit Service fb6fa5
      
Packit Service fb6fa5
      line = _gtk_text_line_next (line);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* Continue propagating as long as the previous resolved forward
Packit Service fb6fa5
   * is different from last_strong.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  {
Packit Service fb6fa5
    GtkTextIter end_propagate;
Packit Service fb6fa5
    
Packit Service fb6fa5
    while (line &&
Packit Service fb6fa5
	   line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
Packit Service fb6fa5
	   line->dir_propagated_forward != last_strong)
Packit Service fb6fa5
      {
Packit Service fb6fa5
        GtkTextLine *prev = line;
Packit Service fb6fa5
        line->dir_propagated_forward = last_strong;
Packit Service fb6fa5
        
Packit Service fb6fa5
        line = _gtk_text_line_next(line);
Packit Service fb6fa5
        if (!line)
Packit Service fb6fa5
          {
Packit Service fb6fa5
            line = prev;
Packit Service fb6fa5
            break;
Packit Service fb6fa5
          }
Packit Service fb6fa5
      }
Packit Service fb6fa5
Packit Service fb6fa5
    /* The last line to invalidate is the last line before the
Packit Service fb6fa5
     * line with the strong character. Or in case of the end of the
Packit Service fb6fa5
     * buffer, the last line of the buffer. (There seems to be an
Packit Service fb6fa5
     * extra "virtual" last line in the buffer that must not be used
Packit Service fb6fa5
     * calling _gtk_text_btree_get_iter_at_line (causes crash). Thus the
Packit Service fb6fa5
     * _gtk_text_line_previous is ok in that case as well.)
Packit Service fb6fa5
     */
Packit Service fb6fa5
    line = _gtk_text_line_previous (line);
Packit Service fb6fa5
    _gtk_text_btree_get_iter_at_line (tree, &end_propagate, line, 0);
Packit Service fb6fa5
    _gtk_text_btree_invalidate_region (tree, end, &end_propagate, FALSE);
Packit Service fb6fa5
  }
Packit Service fb6fa5
  
Packit Service fb6fa5
  /* Sweep backward */
Packit Service fb6fa5
Packit Service fb6fa5
  /* The variable dir_below_propagated contains the backward propagated
Packit Service fb6fa5
   * direction after end. It is neutral if end is at the end of
Packit Service fb6fa5
   * the buffer.
Packit Service fb6fa5
  */
Packit Service fb6fa5
  dir_below_propagated = PANGO_DIRECTION_NEUTRAL;
Packit Service fb6fa5
  if (end_line_next)
Packit Service fb6fa5
    dir_below_propagated = end_line_next->dir_propagated_back;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Loop backward and propagate the direction of each paragraph 
Packit Service fb6fa5
   * to all neutral lines.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  line = end_line;
Packit Service fb6fa5
  last_strong = dir_below_propagated;
Packit Service fb6fa5
  while (line != start_line_prev)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
Packit Service fb6fa5
        last_strong = line->dir_strong;
Packit Service fb6fa5
Packit Service fb6fa5
      line->dir_propagated_back = last_strong;
Packit Service fb6fa5
Packit Service fb6fa5
      line = _gtk_text_line_previous (line);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* Continue propagating as long as the resolved backward dir
Packit Service fb6fa5
   * is different from last_strong.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  {
Packit Service fb6fa5
    GtkTextIter start_propagate;
Packit Service fb6fa5
Packit Service fb6fa5
    while (line &&
Packit Service fb6fa5
	   line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
Packit Service fb6fa5
	   line->dir_propagated_back != last_strong)
Packit Service fb6fa5
      {
Packit Service fb6fa5
        GtkTextLine *prev = line;
Packit Service fb6fa5
        line->dir_propagated_back = last_strong;
Packit Service fb6fa5
Packit Service fb6fa5
        line = _gtk_text_line_previous (line);
Packit Service fb6fa5
        if (!line)
Packit Service fb6fa5
          {
Packit Service fb6fa5
            line = prev;
Packit Service fb6fa5
            break;
Packit Service fb6fa5
          }
Packit Service fb6fa5
      }
Packit Service fb6fa5
Packit Service fb6fa5
    /* We only need to invalidate for backwards propagation if the
Packit Service fb6fa5
     * line we ended up on didn't get a direction from forwards
Packit Service fb6fa5
     * propagation.
Packit Service fb6fa5
     */
Packit Service fb6fa5
    if (line && line->dir_propagated_forward == PANGO_DIRECTION_NEUTRAL)
Packit Service fb6fa5
      {
Packit Service fb6fa5
        _gtk_text_btree_get_iter_at_line (tree, &start_propagate, line, 0);
Packit Service fb6fa5
        _gtk_text_btree_invalidate_region (tree, &start_propagate, start, FALSE);
Packit Service fb6fa5
      }
Packit Service fb6fa5
  }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_delete (GtkTextIter *start,
Packit Service fb6fa5
                        GtkTextIter *end)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *prev_seg;             /* The segment just before the start
Packit Service fb6fa5
                                             * of the deletion range. */
Packit Service fb6fa5
  GtkTextLineSegment *last_seg;             /* The segment just after the end
Packit Service fb6fa5
                                             * of the deletion range. */
Packit Service fb6fa5
  GtkTextLineSegment *seg, *next, *next2;
Packit Service fb6fa5
  GtkTextLine *curline;
Packit Service fb6fa5
  GtkTextBTreeNode *curnode, *node;
Packit Service fb6fa5
  GtkTextBTree *tree;
Packit Service fb6fa5
  GtkTextLine *start_line;
Packit Service fb6fa5
  GtkTextLine *end_line;
Packit Service fb6fa5
  GtkTextLine *line;
Packit Service fb6fa5
  GtkTextLine *deleted_lines = NULL;        /* List of lines we've deleted */
Packit Service fb6fa5
  gint start_byte_offset;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (start != NULL);
Packit Service fb6fa5
  g_return_if_fail (end != NULL);
Packit Service fb6fa5
  g_return_if_fail (_gtk_text_iter_get_btree (start) ==
Packit Service fb6fa5
                    _gtk_text_iter_get_btree (end));
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_text_iter_order (start, end);
Packit Service fb6fa5
Packit Service fb6fa5
  tree = _gtk_text_iter_get_btree (start);
Packit Service fb6fa5
 
Packit Service fb6fa5
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit Service fb6fa5
    _gtk_text_btree_check (tree);
Packit Service fb6fa5
  
Packit Service fb6fa5
  /* Broadcast the need for redisplay before we break the iterators */
Packit Service fb6fa5
  DV (g_print ("invalidating due to deleting some text (%s)\n", G_STRLOC));
Packit Service fb6fa5
  _gtk_text_btree_invalidate_region (tree, start, end, FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Save the byte offset so we can reset the iterators */
Packit Service fb6fa5
  start_byte_offset = gtk_text_iter_get_line_index (start);
Packit Service fb6fa5
Packit Service fb6fa5
  start_line = _gtk_text_iter_get_text_line (start);
Packit Service fb6fa5
  end_line = _gtk_text_iter_get_text_line (end);
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Split the start and end segments, so we have a place
Packit Service fb6fa5
   * to insert our new text.
Packit Service fb6fa5
   *
Packit Service fb6fa5
   * Tricky point:  split at end first;  otherwise the split
Packit Service fb6fa5
   * at end may invalidate seg and/or prev_seg. This allows
Packit Service fb6fa5
   * us to avoid invalidating segments for start.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  last_seg = gtk_text_line_segment_split (end);
Packit Service fb6fa5
  if (last_seg != NULL)
Packit Service fb6fa5
    last_seg = last_seg->next;
Packit Service fb6fa5
  else
Packit Service fb6fa5
    last_seg = end_line->segments;
Packit Service fb6fa5
Packit Service fb6fa5
  prev_seg = gtk_text_line_segment_split (start);
Packit Service fb6fa5
  if (prev_seg != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      seg = prev_seg->next;
Packit Service fb6fa5
      prev_seg->next = last_seg;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      seg = start_line->segments;
Packit Service fb6fa5
      start_line->segments = last_seg;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* notify iterators that their segments need recomputation,
Packit Service fb6fa5
     just for robustness. */
Packit Service fb6fa5
  segments_changed (tree);
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Delete all of the segments between prev_seg and last_seg.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  curline = start_line;
Packit Service fb6fa5
  curnode = curline->parent;
Packit Service fb6fa5
  while (seg != last_seg)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gint char_count = 0;
Packit Service fb6fa5
Packit Service fb6fa5
      if (seg == NULL)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          GtkTextLine *nextline;
Packit Service fb6fa5
Packit Service fb6fa5
          /*
Packit Service fb6fa5
           * We just ran off the end of a line.  First find the
Packit Service fb6fa5
           * next line, then go back to the old line and delete it
Packit Service fb6fa5
           * (unless it's the starting line for the range).
Packit Service fb6fa5
           */
Packit Service fb6fa5
Packit Service fb6fa5
          nextline = _gtk_text_line_next (curline);
Packit Service fb6fa5
          if (curline != start_line)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              if (curnode == start_line->parent)
Packit Service fb6fa5
                start_line->next = curline->next;
Packit Service fb6fa5
              else
Packit Service fb6fa5
                curnode->children.line = curline->next;
Packit Service fb6fa5
Packit Service fb6fa5
              for (node = curnode; node != NULL;
Packit Service fb6fa5
                   node = node->parent)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  /* Don't update node->num_chars, because
Packit Service fb6fa5
                   * that was done when we deleted the segments.
Packit Service fb6fa5
                   */
Packit Service fb6fa5
                  node->num_lines -= 1;
Packit Service fb6fa5
                }
Packit Service fb6fa5
Packit Service fb6fa5
              curnode->num_children -= 1;
Packit Service fb6fa5
              curline->next = deleted_lines;
Packit Service fb6fa5
              deleted_lines = curline;
Packit Service fb6fa5
            }
Packit Service fb6fa5
Packit Service fb6fa5
          curline = nextline;
Packit Service fb6fa5
          seg = curline->segments;
Packit Service fb6fa5
Packit Service fb6fa5
          /*
Packit Service fb6fa5
           * If the GtkTextBTreeNode is empty then delete it and its parents,
Packit Service fb6fa5
           * recursively upwards until a non-empty GtkTextBTreeNode is found.
Packit Service fb6fa5
           */
Packit Service fb6fa5
Packit Service fb6fa5
          while (curnode->num_children == 0)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              GtkTextBTreeNode *parent;
Packit Service fb6fa5
Packit Service fb6fa5
              parent = curnode->parent;
Packit Service fb6fa5
              if (parent->children.node == curnode)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  parent->children.node = curnode->next;
Packit Service fb6fa5
                }
Packit Service fb6fa5
              else
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  GtkTextBTreeNode *prevnode = parent->children.node;
Packit Service fb6fa5
                  while (prevnode->next != curnode)
Packit Service fb6fa5
                    {
Packit Service fb6fa5
                      prevnode = prevnode->next;
Packit Service fb6fa5
                    }
Packit Service fb6fa5
                  prevnode->next = curnode->next;
Packit Service fb6fa5
                }
Packit Service fb6fa5
              parent->num_children--;
Packit Service fb6fa5
              gtk_text_btree_node_free_empty (tree, curnode);
Packit Service fb6fa5
              curnode = parent;
Packit Service fb6fa5
            }
Packit Service fb6fa5
          curnode = curline->parent;
Packit Service fb6fa5
          continue;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      next = seg->next;
Packit Service fb6fa5
      char_count = seg->char_count;
Packit Service fb6fa5
Packit Service fb6fa5
      if ((*seg->type->deleteFunc)(seg, curline, FALSE) != 0)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          /*
Packit Service fb6fa5
           * This segment refuses to die.  Move it to prev_seg and
Packit Service fb6fa5
           * advance prev_seg if the segment has left gravity.
Packit Service fb6fa5
           */
Packit Service fb6fa5
Packit Service fb6fa5
          if (prev_seg == NULL)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              seg->next = start_line->segments;
Packit Service fb6fa5
              start_line->segments = seg;
Packit Service fb6fa5
            }
Packit Service fb6fa5
          else if (prev_seg->next &&
Packit Service fb6fa5
		   prev_seg->next != last_seg &&
Packit Service fb6fa5
		   seg->type == &gtk_text_toggle_off_type &&
Packit Service fb6fa5
		   prev_seg->next->type == &gtk_text_toggle_on_type &&
Packit Service fb6fa5
		   seg->body.toggle.info == prev_seg->next->body.toggle.info)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      /* Try to match an off toggle with the matching on toggle
Packit Service fb6fa5
	       * if it immediately follows. This is a common case, and
Packit Service fb6fa5
	       * handling it here prevents quadratic blowup in
Packit Service fb6fa5
	       * cleanup_line() below. See bug 317125.
Packit Service fb6fa5
	       */
Packit Service fb6fa5
	      next2 = prev_seg->next->next;
Packit Service fb6fa5
	      g_free ((char *)prev_seg->next);
Packit Service fb6fa5
	      prev_seg->next = next2;
Packit Service fb6fa5
	      g_free ((char *)seg);
Packit Service fb6fa5
	      seg = NULL;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	  else
Packit Service fb6fa5
	    {
Packit Service fb6fa5
              seg->next = prev_seg->next;
Packit Service fb6fa5
              prev_seg->next = seg;
Packit Service fb6fa5
            }
Packit Service fb6fa5
Packit Service fb6fa5
          if (seg && seg->type->leftGravity)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              prev_seg = seg;
Packit Service fb6fa5
            }
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else
Packit Service fb6fa5
        {
Packit Service fb6fa5
          /* Segment is gone. Decrement the char count of the node and
Packit Service fb6fa5
             all its parents. */
Packit Service fb6fa5
          for (node = curnode; node != NULL;
Packit Service fb6fa5
               node = node->parent)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              node->num_chars -= char_count;
Packit Service fb6fa5
            }
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      seg = next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * If the beginning and end of the deletion range are in different
Packit Service fb6fa5
   * lines, join the two lines together and discard the ending line.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  if (start_line != end_line)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      BTreeView *view;
Packit Service fb6fa5
      GtkTextBTreeNode *ancestor_node;
Packit Service fb6fa5
      GtkTextLine *prevline;
Packit Service fb6fa5
      int chars_moved;      
Packit Service fb6fa5
Packit Service fb6fa5
      /* last_seg was appended to start_line up at the top of this function */
Packit Service fb6fa5
      chars_moved = 0;
Packit Service fb6fa5
      for (seg = last_seg; seg != NULL;
Packit Service fb6fa5
           seg = seg->next)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          chars_moved += seg->char_count;
Packit Service fb6fa5
          if (seg->type->lineChangeFunc != NULL)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              (*seg->type->lineChangeFunc)(seg, end_line);
Packit Service fb6fa5
            }
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      for (node = start_line->parent; node != NULL;
Packit Service fb6fa5
           node = node->parent)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          node->num_chars += chars_moved;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      
Packit Service fb6fa5
      curnode = end_line->parent;
Packit Service fb6fa5
      for (node = curnode; node != NULL;
Packit Service fb6fa5
           node = node->parent)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          node->num_chars -= chars_moved;
Packit Service fb6fa5
          node->num_lines--;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      curnode->num_children--;
Packit Service fb6fa5
      prevline = curnode->children.line;
Packit Service fb6fa5
      if (prevline == end_line)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          curnode->children.line = end_line->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else
Packit Service fb6fa5
        {
Packit Service fb6fa5
          while (prevline->next != end_line)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              prevline = prevline->next;
Packit Service fb6fa5
            }
Packit Service fb6fa5
          prevline->next = end_line->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      end_line->next = deleted_lines;
Packit Service fb6fa5
      deleted_lines = end_line;
Packit Service fb6fa5
Packit Service fb6fa5
      /* We now fix up the per-view aggregates. We add all the height and
Packit Service fb6fa5
       * width for the deleted lines to the start line, so that when revalidation
Packit Service fb6fa5
       * occurs, the correct change in size is seen.
Packit Service fb6fa5
       */
Packit Service fb6fa5
      ancestor_node = gtk_text_btree_node_common_parent (curnode, start_line->parent);
Packit Service fb6fa5
      view = tree->views;
Packit Service fb6fa5
      while (view)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          GtkTextLineData *ld;
Packit Service fb6fa5
Packit Service fb6fa5
          gint deleted_width = 0;
Packit Service fb6fa5
          gint deleted_height = 0;
Packit Service fb6fa5
Packit Service fb6fa5
          line = deleted_lines;
Packit Service fb6fa5
          while (line)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              GtkTextLine *next_line = line->next;
Packit Service fb6fa5
              ld = _gtk_text_line_get_data (line, view->view_id);
Packit Service fb6fa5
Packit Service fb6fa5
              if (ld)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  deleted_width = MAX (deleted_width, ld->width);
Packit Service fb6fa5
                  deleted_height += ld->height;
Packit Service fb6fa5
                }
Packit Service fb6fa5
Packit Service fb6fa5
              line = next_line;
Packit Service fb6fa5
            }
Packit Service fb6fa5
Packit Service fb6fa5
          if (deleted_width > 0 || deleted_height > 0)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              ld = _gtk_text_line_get_data (start_line, view->view_id);
Packit Service fb6fa5
              
Packit Service fb6fa5
              if (ld == NULL)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  /* This means that start_line has never been validated.
Packit Service fb6fa5
                   * We don't really want to do the validation here but
Packit Service fb6fa5
                   * we do need to store our temporary sizes. So we
Packit Service fb6fa5
                   * create the line data and assume a line w/h of 0.
Packit Service fb6fa5
                   */
Packit Service fb6fa5
                  ld = _gtk_text_line_data_new (view->layout, start_line);
Packit Service fb6fa5
                  _gtk_text_line_add_data (start_line, ld);
Packit Service fb6fa5
                  ld->width = 0;
Packit Service fb6fa5
                  ld->height = 0;
Packit Service fb6fa5
                  ld->valid = FALSE;
Packit Service fb6fa5
                }
Packit Service fb6fa5
              
Packit Service fb6fa5
              ld->width = MAX (deleted_width, ld->width);
Packit Service fb6fa5
              ld->height += deleted_height;
Packit Service fb6fa5
              ld->valid = FALSE;
Packit Service fb6fa5
            }
Packit Service fb6fa5
Packit Service fb6fa5
          gtk_text_btree_node_check_valid_downward (ancestor_node, view->view_id);
Packit Service fb6fa5
          if (ancestor_node->parent)
Packit Service fb6fa5
            gtk_text_btree_node_check_valid_upward (ancestor_node->parent, view->view_id);
Packit Service fb6fa5
Packit Service fb6fa5
          view = view->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      line = deleted_lines;
Packit Service fb6fa5
      while (line)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          GtkTextLine *next_line = line->next;
Packit Service fb6fa5
Packit Service fb6fa5
          gtk_text_line_destroy (tree, line);
Packit Service fb6fa5
Packit Service fb6fa5
          line = next_line;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      /* avoid dangling pointer */
Packit Service fb6fa5
      deleted_lines = NULL;
Packit Service fb6fa5
      
Packit Service fb6fa5
      gtk_text_btree_rebalance (tree, curnode);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Cleanup the segments in the new line.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  cleanup_line (start_line);
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Lastly, rebalance the first GtkTextBTreeNode of the range.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_text_btree_rebalance (tree, start_line->parent);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Notify outstanding iterators that they
Packit Service fb6fa5
     are now hosed */
Packit Service fb6fa5
  chars_changed (tree);
Packit Service fb6fa5
  segments_changed (tree);
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit Service fb6fa5
    _gtk_text_btree_check (tree);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Re-initialize our iterators */
Packit Service fb6fa5
  _gtk_text_btree_get_iter_at_line (tree, start, start_line, start_byte_offset);
Packit Service fb6fa5
  *end = *start;
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_text_btree_resolve_bidi (start, end);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_insert (GtkTextIter *iter,
Packit Service fb6fa5
                        const gchar *text,
Packit Service fb6fa5
                        gint         len)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *prev_seg;     /* The segment just before the first
Packit Service fb6fa5
                                     * new segment (NULL means new segment
Packit Service fb6fa5
                                     * is at beginning of line). */
Packit Service fb6fa5
  GtkTextLineSegment *cur_seg;              /* Current segment;  new characters
Packit Service fb6fa5
                                             * are inserted just after this one.
Packit Service fb6fa5
                                             * NULL means insert at beginning of
Packit Service fb6fa5
                                             * line. */
Packit Service fb6fa5
  GtkTextLine *line;           /* Current line (new segments are
Packit Service fb6fa5
                                * added to this line). */
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  GtkTextLine *newline;
Packit Service fb6fa5
  int chunk_len;                        /* # characters in current chunk. */
Packit Service fb6fa5
  gint sol;                           /* start of line */
Packit Service fb6fa5
  gint eol;                           /* Pointer to character just after last
Packit Service fb6fa5
                                       * one in current chunk.
Packit Service fb6fa5
                                       */
Packit Service fb6fa5
  gint delim;                          /* index of paragraph delimiter */
Packit Service fb6fa5
  int line_count_delta;                /* Counts change to total number of
Packit Service fb6fa5
                                        * lines in file.
Packit Service fb6fa5
                                        */
Packit Service fb6fa5
Packit Service fb6fa5
  int char_count_delta;                /* change to number of chars */
Packit Service fb6fa5
  GtkTextBTree *tree;
Packit Service fb6fa5
  gint start_byte_index;
Packit Service fb6fa5
  GtkTextLine *start_line;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (text != NULL);
Packit Service fb6fa5
  g_return_if_fail (iter != NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  if (len < 0)
Packit Service fb6fa5
    len = strlen (text);
Packit Service fb6fa5
Packit Service fb6fa5
  /* extract iterator info */
Packit Service fb6fa5
  tree = _gtk_text_iter_get_btree (iter);
Packit Service fb6fa5
  line = _gtk_text_iter_get_text_line (iter);
Packit Service fb6fa5
  
Packit Service fb6fa5
  start_line = line;
Packit Service fb6fa5
  start_byte_index = gtk_text_iter_get_line_index (iter);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Get our insertion segment split. Note this assumes line allows
Packit Service fb6fa5
   * char insertions, which isn't true of the "last" line. But iter
Packit Service fb6fa5
   * should not be on that line, as we assert here.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  g_assert (!_gtk_text_line_is_last (line, tree));
Packit Service fb6fa5
  prev_seg = gtk_text_line_segment_split (iter);
Packit Service fb6fa5
  cur_seg = prev_seg;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Invalidate all iterators */
Packit Service fb6fa5
  chars_changed (tree);
Packit Service fb6fa5
  segments_changed (tree);
Packit Service fb6fa5
  
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Chop the text up into lines and create a new segment for
Packit Service fb6fa5
   * each line, plus a new line for the leftovers from the
Packit Service fb6fa5
   * previous line.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  eol = 0;
Packit Service fb6fa5
  sol = 0;
Packit Service fb6fa5
  line_count_delta = 0;
Packit Service fb6fa5
  char_count_delta = 0;
Packit Service fb6fa5
  while (eol < len)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      sol = eol;
Packit Service fb6fa5
      
Packit Service fb6fa5
      pango_find_paragraph_boundary (text + sol,
Packit Service fb6fa5
                                     len - sol,
Packit Service fb6fa5
                                     &delim,
Packit Service fb6fa5
                                     &eol;;      
Packit Service fb6fa5
Packit Service fb6fa5
      /* make these relative to the start of the text */
Packit Service fb6fa5
      delim += sol;
Packit Service fb6fa5
      eol += sol;
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (eol >= sol);
Packit Service fb6fa5
      g_assert (delim >= sol);
Packit Service fb6fa5
      g_assert (eol >= delim);
Packit Service fb6fa5
      g_assert (sol >= 0);
Packit Service fb6fa5
      g_assert (eol <= len);
Packit Service fb6fa5
      
Packit Service fb6fa5
      chunk_len = eol - sol;
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (g_utf8_validate (&text[sol], chunk_len, NULL));
Packit Service fb6fa5
      seg = _gtk_char_segment_new (&text[sol], chunk_len);
Packit Service fb6fa5
Packit Service fb6fa5
      char_count_delta += seg->char_count;
Packit Service fb6fa5
Packit Service fb6fa5
      if (cur_seg == NULL)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          seg->next = line->segments;
Packit Service fb6fa5
          line->segments = seg;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else
Packit Service fb6fa5
        {
Packit Service fb6fa5
          seg->next = cur_seg->next;
Packit Service fb6fa5
          cur_seg->next = seg;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      if (delim == eol)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          /* chunk didn't end with a paragraph separator */
Packit Service fb6fa5
          g_assert (eol == len);
Packit Service fb6fa5
          break;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      /*
Packit Service fb6fa5
       * The chunk ended with a newline, so create a new GtkTextLine
Packit Service fb6fa5
       * and move the remainder of the old line to it.
Packit Service fb6fa5
       */
Packit Service fb6fa5
Packit Service fb6fa5
      newline = gtk_text_line_new ();
Packit Service fb6fa5
      gtk_text_line_set_parent (newline, line->parent);
Packit Service fb6fa5
      newline->next = line->next;
Packit Service fb6fa5
      line->next = newline;
Packit Service fb6fa5
      newline->segments = seg->next;
Packit Service fb6fa5
      seg->next = NULL;
Packit Service fb6fa5
      line = newline;
Packit Service fb6fa5
      cur_seg = NULL;
Packit Service fb6fa5
      line_count_delta++;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Cleanup the starting line for the insertion, plus the ending
Packit Service fb6fa5
   * line if it's different.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  cleanup_line (start_line);
Packit Service fb6fa5
  if (line != start_line)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      cleanup_line (line);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  post_insert_fixup (tree, line, line_count_delta, char_count_delta);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Invalidate our region, and reset the iterator the user
Packit Service fb6fa5
     passed in to point to the end of the inserted text. */
Packit Service fb6fa5
  {
Packit Service fb6fa5
    GtkTextIter start;
Packit Service fb6fa5
    GtkTextIter end;
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
    _gtk_text_btree_get_iter_at_line (tree,
Packit Service fb6fa5
                                      &start,
Packit Service fb6fa5
                                      start_line,
Packit Service fb6fa5
                                      start_byte_index);
Packit Service fb6fa5
    end = start;
Packit Service fb6fa5
Packit Service fb6fa5
    /* We could almost certainly be more efficient here
Packit Service fb6fa5
       by saving the information from the insertion loop
Packit Service fb6fa5
       above. FIXME */
Packit Service fb6fa5
    gtk_text_iter_forward_chars (&end, char_count_delta);
Packit Service fb6fa5
Packit Service fb6fa5
    DV (g_print ("invalidating due to inserting some text (%s)\n", G_STRLOC));
Packit Service fb6fa5
    _gtk_text_btree_invalidate_region (tree, &start, &end, FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
    /* Convenience for the user */
Packit Service fb6fa5
    *iter = end;
Packit Service fb6fa5
Packit Service fb6fa5
    gtk_text_btree_resolve_bidi (&start, &end;;
Packit Service fb6fa5
  }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
insert_pixbuf_or_widget_segment (GtkTextIter        *iter,
Packit Service fb6fa5
                                 GtkTextLineSegment *seg)
Packit Service fb6fa5
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextIter start;
Packit Service fb6fa5
  GtkTextLineSegment *prevPtr;
Packit Service fb6fa5
  GtkTextLine *line;
Packit Service fb6fa5
  GtkTextBTree *tree;
Packit Service fb6fa5
  gint start_byte_offset;
Packit Service fb6fa5
Packit Service fb6fa5
  line = _gtk_text_iter_get_text_line (iter);
Packit Service fb6fa5
  tree = _gtk_text_iter_get_btree (iter);
Packit Service fb6fa5
  start_byte_offset = gtk_text_iter_get_line_index (iter);
Packit Service fb6fa5
Packit Service fb6fa5
  prevPtr = gtk_text_line_segment_split (iter);
Packit Service fb6fa5
  if (prevPtr == NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      seg->next = line->segments;
Packit Service fb6fa5
      line->segments = seg;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      seg->next = prevPtr->next;
Packit Service fb6fa5
      prevPtr->next = seg;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  post_insert_fixup (tree, line, 0, seg->char_count);
Packit Service fb6fa5
Packit Service fb6fa5
  chars_changed (tree);
Packit Service fb6fa5
  segments_changed (tree);
Packit Service fb6fa5
Packit Service fb6fa5
  /* reset *iter for the user, and invalidate tree nodes */
Packit Service fb6fa5
Packit Service fb6fa5
  _gtk_text_btree_get_iter_at_line (tree, &start, line, start_byte_offset);
Packit Service fb6fa5
Packit Service fb6fa5
  *iter = start;
Packit Service fb6fa5
  gtk_text_iter_forward_char (iter); /* skip forward past the segment */
Packit Service fb6fa5
Packit Service fb6fa5
  DV (g_print ("invalidating due to inserting pixbuf/widget (%s)\n", G_STRLOC));
Packit Service fb6fa5
  _gtk_text_btree_invalidate_region (tree, &start, iter, FALSE);
Packit Service fb6fa5
}
Packit Service fb6fa5
     
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_insert_pixbuf (GtkTextIter *iter,
Packit Service fb6fa5
                              GdkPixbuf   *pixbuf)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  
Packit Service fb6fa5
  seg = _gtk_pixbuf_segment_new (pixbuf);
Packit Service fb6fa5
Packit Service fb6fa5
  insert_pixbuf_or_widget_segment (iter, seg);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_insert_child_anchor (GtkTextIter        *iter,
Packit Service fb6fa5
                                     GtkTextChildAnchor *anchor)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  GtkTextBTree *tree;
Packit Service fb6fa5
Packit Service fb6fa5
  if (anchor->segment != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_warning (G_STRLOC": Same child anchor can't be inserted twice");
Packit Service fb6fa5
      return;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  
Packit Service fb6fa5
  seg = _gtk_widget_segment_new (anchor);
Packit Service fb6fa5
Packit Service fb6fa5
  tree = seg->body.child.tree = _gtk_text_iter_get_btree (iter);
Packit Service fb6fa5
  seg->body.child.line = _gtk_text_iter_get_text_line (iter);
Packit Service fb6fa5
  
Packit Service fb6fa5
  insert_pixbuf_or_widget_segment (iter, seg);
Packit Service fb6fa5
Packit Service fb6fa5
  if (tree->child_anchor_table == NULL)
Packit Service fb6fa5
    tree->child_anchor_table = g_hash_table_new (NULL, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  g_hash_table_insert (tree->child_anchor_table,
Packit Service fb6fa5
                       seg->body.child.obj,
Packit Service fb6fa5
                       seg->body.child.obj);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_unregister_child_anchor (GtkTextChildAnchor *anchor)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
Packit Service fb6fa5
  seg = anchor->segment;
Packit Service fb6fa5
  
Packit Service fb6fa5
  g_hash_table_remove (seg->body.child.tree->child_anchor_table,
Packit Service fb6fa5
                       anchor);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * View stuff
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
static GtkTextLine*
Packit Service fb6fa5
find_line_by_y (GtkTextBTree *tree, BTreeView *view,
Packit Service fb6fa5
                GtkTextBTreeNode *node, gint y, gint *line_top,
Packit Service fb6fa5
                GtkTextLine *last_line)
Packit Service fb6fa5
{
Packit Service fb6fa5
  gint current_y = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit Service fb6fa5
    _gtk_text_btree_check (tree);
Packit Service fb6fa5
Packit Service fb6fa5
  if (node->level == 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkTextLine *line;
Packit Service fb6fa5
Packit Service fb6fa5
      line = node->children.line;
Packit Service fb6fa5
Packit Service fb6fa5
      while (line != NULL && line != last_line)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          GtkTextLineData *ld;
Packit Service fb6fa5
Packit Service fb6fa5
          ld = _gtk_text_line_get_data (line, view->view_id);
Packit Service fb6fa5
Packit Service fb6fa5
          if (ld)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              if (y < (current_y + (ld ? ld->height : 0)))
Packit Service fb6fa5
                return line;
Packit Service fb6fa5
Packit Service fb6fa5
              current_y += ld->height;
Packit Service fb6fa5
              *line_top += ld->height;
Packit Service fb6fa5
            }
Packit Service fb6fa5
Packit Service fb6fa5
          line = line->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      return NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkTextBTreeNode *child;
Packit Service fb6fa5
Packit Service fb6fa5
      child = node->children.node;
Packit Service fb6fa5
Packit Service fb6fa5
      while (child != NULL)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          gint width;
Packit Service fb6fa5
          gint height;
Packit Service fb6fa5
Packit Service fb6fa5
          gtk_text_btree_node_get_size (child, view->view_id,
Packit Service fb6fa5
                                        &width, &height);
Packit Service fb6fa5
Packit Service fb6fa5
          if (y < (current_y + height))
Packit Service fb6fa5
            return find_line_by_y (tree, view, child,
Packit Service fb6fa5
                                   y - current_y, line_top,
Packit Service fb6fa5
                                   last_line);
Packit Service fb6fa5
Packit Service fb6fa5
          current_y += height;
Packit Service fb6fa5
          *line_top += height;
Packit Service fb6fa5
Packit Service fb6fa5
          child = child->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      return NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextLine *
Packit Service fb6fa5
_gtk_text_btree_find_line_by_y (GtkTextBTree *tree,
Packit Service fb6fa5
                                gpointer      view_id,
Packit Service fb6fa5
                                gint          ypixel,
Packit Service fb6fa5
                                gint         *line_top_out)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLine *line;
Packit Service fb6fa5
  BTreeView *view;
Packit Service fb6fa5
  GtkTextLine *last_line;
Packit Service fb6fa5
  gint line_top = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  view = gtk_text_btree_get_view (tree, view_id);
Packit Service fb6fa5
  g_return_val_if_fail (view != NULL, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  last_line = get_last_line (tree);
Packit Service fb6fa5
Packit Service fb6fa5
  line = find_line_by_y (tree, view, tree->root_node, ypixel, &line_top,
Packit Service fb6fa5
                         last_line);
Packit Service fb6fa5
Packit Service fb6fa5
  if (line_top_out)
Packit Service fb6fa5
    *line_top_out = line_top;
Packit Service fb6fa5
Packit Service fb6fa5
  return line;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gint
Packit Service fb6fa5
find_line_top_in_line_list (GtkTextBTree *tree,
Packit Service fb6fa5
                            BTreeView *view,
Packit Service fb6fa5
                            GtkTextLine *line,
Packit Service fb6fa5
                            GtkTextLine *target_line,
Packit Service fb6fa5
                            gint y)
Packit Service fb6fa5
{
Packit Service fb6fa5
  while (line != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkTextLineData *ld;
Packit Service fb6fa5
Packit Service fb6fa5
      if (line == target_line)
Packit Service fb6fa5
        return y;
Packit Service fb6fa5
Packit Service fb6fa5
      ld = _gtk_text_line_get_data (line, view->view_id);
Packit Service fb6fa5
      if (ld)
Packit Service fb6fa5
        y += ld->height;
Packit Service fb6fa5
Packit Service fb6fa5
      line = line->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  g_assert_not_reached (); /* If we get here, our
Packit Service fb6fa5
                              target line didn't exist
Packit Service fb6fa5
                              under its parent node */
Packit Service fb6fa5
  return 0;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
gint
Packit Service fb6fa5
_gtk_text_btree_find_line_top (GtkTextBTree *tree,
Packit Service fb6fa5
                              GtkTextLine *target_line,
Packit Service fb6fa5
                              gpointer view_id)
Packit Service fb6fa5
{
Packit Service fb6fa5
  gint y = 0;
Packit Service fb6fa5
  BTreeView *view;
Packit Service fb6fa5
  GSList *nodes;
Packit Service fb6fa5
  GSList *iter;
Packit Service fb6fa5
  GtkTextBTreeNode *node;
Packit Service fb6fa5
Packit Service fb6fa5
  view = gtk_text_btree_get_view (tree, view_id);
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (view != NULL, 0);
Packit Service fb6fa5
Packit Service fb6fa5
  nodes = NULL;
Packit Service fb6fa5
  node = target_line->parent;
Packit Service fb6fa5
  while (node != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      nodes = g_slist_prepend (nodes, node);
Packit Service fb6fa5
      node = node->parent;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  iter = nodes;
Packit Service fb6fa5
  while (iter != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      node = iter->data;
Packit Service fb6fa5
Packit Service fb6fa5
      if (node->level == 0)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          g_slist_free (nodes);
Packit Service fb6fa5
          return find_line_top_in_line_list (tree, view,
Packit Service fb6fa5
                                             node->children.line,
Packit Service fb6fa5
                                             target_line, y);
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else
Packit Service fb6fa5
        {
Packit Service fb6fa5
          GtkTextBTreeNode *child;
Packit Service fb6fa5
          GtkTextBTreeNode *target_node;
Packit Service fb6fa5
Packit Service fb6fa5
          g_assert (iter->next != NULL); /* not at level 0 */
Packit Service fb6fa5
          target_node = iter->next->data;
Packit Service fb6fa5
Packit Service fb6fa5
          child = node->children.node;
Packit Service fb6fa5
Packit Service fb6fa5
          while (child != NULL)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              gint width;
Packit Service fb6fa5
              gint height;
Packit Service fb6fa5
Packit Service fb6fa5
              if (child == target_node)
Packit Service fb6fa5
                break;
Packit Service fb6fa5
              else
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  gtk_text_btree_node_get_size (child, view->view_id,
Packit Service fb6fa5
                                                &width, &height);
Packit Service fb6fa5
                  y += height;
Packit Service fb6fa5
                }
Packit Service fb6fa5
              child = child->next;
Packit Service fb6fa5
            }
Packit Service fb6fa5
          g_assert (child != NULL); /* should have broken out before we
Packit Service fb6fa5
                                       ran out of nodes */
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      iter = g_slist_next (iter);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  g_assert_not_reached (); /* we return when we find the target line */
Packit Service fb6fa5
  return 0;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_add_view (GtkTextBTree *tree,
Packit Service fb6fa5
                         GtkTextLayout *layout)
Packit Service fb6fa5
{
Packit Service fb6fa5
  BTreeView *view;
Packit Service fb6fa5
  GtkTextLine *last_line;
Packit Service fb6fa5
  GtkTextLineData *line_data;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (tree != NULL);
Packit Service fb6fa5
  
Packit Service fb6fa5
  view = g_new (BTreeView, 1);
Packit Service fb6fa5
Packit Service fb6fa5
  view->view_id = layout;
Packit Service fb6fa5
  view->layout = layout;
Packit Service fb6fa5
Packit Service fb6fa5
  view->next = tree->views;
Packit Service fb6fa5
  view->prev = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  if (tree->views)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_assert (tree->views->prev == NULL);
Packit Service fb6fa5
      tree->views->prev = view;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  
Packit Service fb6fa5
  tree->views = view;
Packit Service fb6fa5
Packit Service fb6fa5
  /* The last line in the buffer has identity values for the per-view
Packit Service fb6fa5
   * data so that we can avoid special case checks for it in a large
Packit Service fb6fa5
   * number of loops
Packit Service fb6fa5
   */
Packit Service fb6fa5
  last_line = get_last_line (tree);
Packit Service fb6fa5
Packit Service fb6fa5
  line_data = g_new (GtkTextLineData, 1);
Packit Service fb6fa5
  line_data->view_id = layout;
Packit Service fb6fa5
  line_data->next = NULL;
Packit Service fb6fa5
  line_data->width = 0;
Packit Service fb6fa5
  line_data->height = 0;
Packit Service fb6fa5
  line_data->valid = TRUE;
Packit Service fb6fa5
Packit Service fb6fa5
  _gtk_text_line_add_data (last_line, line_data);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_remove_view (GtkTextBTree *tree,
Packit Service fb6fa5
                             gpointer      view_id)
Packit Service fb6fa5
{
Packit Service fb6fa5
  BTreeView *view;
Packit Service fb6fa5
  GtkTextLine *last_line;
Packit Service fb6fa5
  GtkTextLineData *line_data;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (tree != NULL);
Packit Service fb6fa5
  
Packit Service fb6fa5
  view = tree->views;
Packit Service fb6fa5
Packit Service fb6fa5
  while (view != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (view->view_id == view_id)
Packit Service fb6fa5
        break;
Packit Service fb6fa5
Packit Service fb6fa5
      view = view->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (view != NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  if (view->next)
Packit Service fb6fa5
    view->next->prev = view->prev;
Packit Service fb6fa5
Packit Service fb6fa5
  if (view->prev)
Packit Service fb6fa5
    view->prev->next = view->next;
Packit Service fb6fa5
Packit Service fb6fa5
  if (view == tree->views)
Packit Service fb6fa5
    tree->views = view->next;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Remove the line data for the last line which we added ourselves.
Packit Service fb6fa5
   * (Do this first, so that we don't try to call the view's line data destructor on it.)
Packit Service fb6fa5
   */
Packit Service fb6fa5
  last_line = get_last_line (tree);
Packit Service fb6fa5
  line_data = _gtk_text_line_remove_data (last_line, view_id);
Packit Service fb6fa5
  g_free (line_data);
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_text_btree_node_remove_view (view, tree->root_node, view_id);
Packit Service fb6fa5
Packit Service fb6fa5
  view->layout = (gpointer) 0xdeadbeef;
Packit Service fb6fa5
  view->view_id = (gpointer) 0xdeadbeef;
Packit Service fb6fa5
  
Packit Service fb6fa5
  g_free (view);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_invalidate_region (GtkTextBTree      *tree,
Packit Service fb6fa5
                                   const GtkTextIter *start,
Packit Service fb6fa5
                                   const GtkTextIter *end,
Packit Service fb6fa5
                                   gboolean           cursors_only)
Packit Service fb6fa5
{
Packit Service fb6fa5
  BTreeView *view;
Packit Service fb6fa5
Packit Service fb6fa5
  view = tree->views;
Packit Service fb6fa5
Packit Service fb6fa5
  while (view != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (cursors_only)
Packit Service fb6fa5
	gtk_text_layout_invalidate_cursors (view->layout, start, end);
Packit Service fb6fa5
      else
Packit Service fb6fa5
	gtk_text_layout_invalidate (view->layout, start, end);
Packit Service fb6fa5
Packit Service fb6fa5
      view = view->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_get_view_size (GtkTextBTree *tree,
Packit Service fb6fa5
                              gpointer view_id,
Packit Service fb6fa5
                              gint *width,
Packit Service fb6fa5
                              gint *height)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_return_if_fail (tree != NULL);
Packit Service fb6fa5
  g_return_if_fail (view_id != NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_text_btree_node_get_size (tree->root_node, view_id,
Packit Service fb6fa5
                                width, height);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Tag
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct {
Packit Service fb6fa5
  GtkTextIter *iters;
Packit Service fb6fa5
  guint count;
Packit Service fb6fa5
  guint alloced;
Packit Service fb6fa5
} IterStack;
Packit Service fb6fa5
Packit Service fb6fa5
static IterStack*
Packit Service fb6fa5
iter_stack_new (void)
Packit Service fb6fa5
{
Packit Service fb6fa5
  IterStack *stack;
Packit Service fb6fa5
  stack = g_slice_new (IterStack);
Packit Service fb6fa5
  stack->iters = NULL;
Packit Service fb6fa5
  stack->count = 0;
Packit Service fb6fa5
  stack->alloced = 0;
Packit Service fb6fa5
  return stack;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
iter_stack_push (IterStack         *stack, 
Packit Service fb6fa5
		 const GtkTextIter *iter)
Packit Service fb6fa5
{
Packit Service fb6fa5
  stack->count += 1;
Packit Service fb6fa5
  if (stack->count > stack->alloced)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      stack->alloced = stack->count*2;
Packit Service fb6fa5
      stack->iters = g_realloc (stack->iters,
Packit Service fb6fa5
                                stack->alloced * sizeof (GtkTextIter));
Packit Service fb6fa5
    }
Packit Service fb6fa5
  stack->iters[stack->count-1] = *iter;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
iter_stack_pop (IterStack   *stack, 
Packit Service fb6fa5
		GtkTextIter *iter)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (stack->count == 0)
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      stack->count -= 1;
Packit Service fb6fa5
      *iter = stack->iters[stack->count];
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
iter_stack_free (IterStack *stack)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_free (stack->iters);
Packit Service fb6fa5
  g_slice_free (IterStack, stack);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
iter_stack_invert (IterStack *stack)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (stack->count > 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      guint i = 0;
Packit Service fb6fa5
      guint j = stack->count - 1;
Packit Service fb6fa5
      while (i < j)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          GtkTextIter tmp;
Packit Service fb6fa5
Packit Service fb6fa5
          tmp = stack->iters[i];
Packit Service fb6fa5
          stack->iters[i] = stack->iters[j];
Packit Service fb6fa5
          stack->iters[j] = tmp;
Packit Service fb6fa5
Packit Service fb6fa5
          ++i;
Packit Service fb6fa5
          --j;
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
queue_tag_redisplay (GtkTextBTree      *tree,
Packit Service fb6fa5
                     GtkTextTag        *tag,
Packit Service fb6fa5
                     const GtkTextIter *start,
Packit Service fb6fa5
                     const GtkTextIter *end)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (_gtk_text_tag_affects_size (tag))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      DV (g_print ("invalidating due to size-affecting tag (%s)\n", G_STRLOC));
Packit Service fb6fa5
      _gtk_text_btree_invalidate_region (tree, start, end, FALSE);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (_gtk_text_tag_affects_nonsize_appearance (tag))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* We only need to queue a redraw, not a relayout */
Packit Service fb6fa5
      redisplay_region (tree, start, end, FALSE);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* We don't need to do anything if the tag doesn't affect display */
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_tag (const GtkTextIter *start_orig,
Packit Service fb6fa5
                     const GtkTextIter *end_orig,
Packit Service fb6fa5
                     GtkTextTag        *tag,
Packit Service fb6fa5
                     gboolean           add)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg, *prev;
Packit Service fb6fa5
  GtkTextLine *cleanupline;
Packit Service fb6fa5
  gboolean toggled_on;
Packit Service fb6fa5
  GtkTextLine *start_line;
Packit Service fb6fa5
  GtkTextLine *end_line;
Packit Service fb6fa5
  GtkTextIter iter;
Packit Service fb6fa5
  GtkTextIter start, end;
Packit Service fb6fa5
  GtkTextBTree *tree;
Packit Service fb6fa5
  IterStack *stack;
Packit Service fb6fa5
  GtkTextTagInfo *info;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (start_orig != NULL);
Packit Service fb6fa5
  g_return_if_fail (end_orig != NULL);
Packit Service fb6fa5
  g_return_if_fail (GTK_IS_TEXT_TAG (tag));
Packit Service fb6fa5
  g_return_if_fail (_gtk_text_iter_get_btree (start_orig) ==
Packit Service fb6fa5
                    _gtk_text_iter_get_btree (end_orig));
Packit Service fb6fa5
  g_return_if_fail (tag->table == _gtk_text_iter_get_btree (start_orig)->table);
Packit Service fb6fa5
  
Packit Service fb6fa5
#if 0
Packit Service fb6fa5
  printf ("%s tag %s from %d to %d\n",
Packit Service fb6fa5
          add ? "Adding" : "Removing",
Packit Service fb6fa5
          tag->name,
Packit Service fb6fa5
          gtk_text_buffer_get_offset (start_orig),
Packit Service fb6fa5
          gtk_text_buffer_get_offset (end_orig));
Packit Service fb6fa5
#endif
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_text_iter_equal (start_orig, end_orig))
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  start = *start_orig;
Packit Service fb6fa5
  end = *end_orig;
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_text_iter_order (&start, &end;;
Packit Service fb6fa5
Packit Service fb6fa5
  tree = _gtk_text_iter_get_btree (&start;;
Packit Service fb6fa5
Packit Service fb6fa5
  queue_tag_redisplay (tree, tag, &start, &end;;
Packit Service fb6fa5
Packit Service fb6fa5
  info = gtk_text_btree_get_tag_info (tree, tag);
Packit Service fb6fa5
Packit Service fb6fa5
  start_line = _gtk_text_iter_get_text_line (&start;;
Packit Service fb6fa5
  end_line = _gtk_text_iter_get_text_line (&end;;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Find all tag toggles in the region; we are going to delete them.
Packit Service fb6fa5
     We need to find them in advance, because
Packit Service fb6fa5
     forward_find_tag_toggle () won't work once we start playing around
Packit Service fb6fa5
     with the tree. */
Packit Service fb6fa5
  stack = iter_stack_new ();
Packit Service fb6fa5
  iter = start;
Packit Service fb6fa5
Packit Service fb6fa5
  /* forward_to_tag_toggle() skips a toggle at the start iterator,
Packit Service fb6fa5
   * which is deliberate - we don't want to delete a toggle at the
Packit Service fb6fa5
   * start.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  while (gtk_text_iter_forward_to_tag_toggle (&iter, tag))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (gtk_text_iter_compare (&iter, &end) >= 0)
Packit Service fb6fa5
        break;
Packit Service fb6fa5
      else
Packit Service fb6fa5
        iter_stack_push (stack, &iter);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* We need to traverse the toggles in order. */
Packit Service fb6fa5
  iter_stack_invert (stack);
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * See whether the tag is present at the start of the range.  If
Packit Service fb6fa5
   * the state doesn't already match what we want then add a toggle
Packit Service fb6fa5
   * there.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  toggled_on = gtk_text_iter_has_tag (&start, tag);
Packit Service fb6fa5
  if ( (add && !toggled_on) ||
Packit Service fb6fa5
       (!add && toggled_on) )
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* This could create a second toggle at the start position;
Packit Service fb6fa5
         cleanup_line () will remove it if so. */
Packit Service fb6fa5
      seg = _gtk_toggle_segment_new (info, add);
Packit Service fb6fa5
Packit Service fb6fa5
      prev = gtk_text_line_segment_split (&start;;
Packit Service fb6fa5
      if (prev == NULL)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          seg->next = start_line->segments;
Packit Service fb6fa5
          start_line->segments = seg;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else
Packit Service fb6fa5
        {
Packit Service fb6fa5
          seg->next = prev->next;
Packit Service fb6fa5
          prev->next = seg;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      /* cleanup_line adds the new toggle to the node counts. */
Packit Service fb6fa5
#if 0
Packit Service fb6fa5
      printf ("added toggle at start\n");
Packit Service fb6fa5
#endif
Packit Service fb6fa5
      /* we should probably call segments_changed, but in theory
Packit Service fb6fa5
         any still-cached segments in the iters we are about to
Packit Service fb6fa5
         use are still valid, since they're in front
Packit Service fb6fa5
         of this spot. */
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   *
Packit Service fb6fa5
   * Scan the range of characters and delete any internal tag
Packit Service fb6fa5
   * transitions.  Keep track of what the old state was at the end
Packit Service fb6fa5
   * of the range, and add a toggle there if it's needed.
Packit Service fb6fa5
   *
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  cleanupline = start_line;
Packit Service fb6fa5
  while (iter_stack_pop (stack, &iter))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkTextLineSegment *indexable_seg;
Packit Service fb6fa5
      GtkTextLine *line;
Packit Service fb6fa5
Packit Service fb6fa5
      line = _gtk_text_iter_get_text_line (&iter);
Packit Service fb6fa5
      seg = _gtk_text_iter_get_any_segment (&iter);
Packit Service fb6fa5
      indexable_seg = _gtk_text_iter_get_indexable_segment (&iter);
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (seg != NULL);
Packit Service fb6fa5
      g_assert (indexable_seg != NULL);
Packit Service fb6fa5
      g_assert (seg != indexable_seg);
Packit Service fb6fa5
Packit Service fb6fa5
      prev = line->segments;
Packit Service fb6fa5
Packit Service fb6fa5
      /* Find the segment that actually toggles this tag. */
Packit Service fb6fa5
      while (seg != indexable_seg)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          g_assert (seg != NULL);
Packit Service fb6fa5
          g_assert (indexable_seg != NULL);
Packit Service fb6fa5
          g_assert (seg != indexable_seg);
Packit Service fb6fa5
          
Packit Service fb6fa5
          if ( (seg->type == &gtk_text_toggle_on_type ||
Packit Service fb6fa5
                seg->type == &gtk_text_toggle_off_type) &&
Packit Service fb6fa5
               (seg->body.toggle.info == info) )
Packit Service fb6fa5
            break;
Packit Service fb6fa5
          else
Packit Service fb6fa5
            seg = seg->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (seg != NULL);
Packit Service fb6fa5
      g_assert (indexable_seg != NULL);
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (seg != indexable_seg); /* If this happens, then
Packit Service fb6fa5
                                          forward_to_tag_toggle was
Packit Service fb6fa5
                                          full of shit. */
Packit Service fb6fa5
      g_assert (seg->body.toggle.info->tag == tag);
Packit Service fb6fa5
Packit Service fb6fa5
      /* If this happens, when previously tagging we didn't merge
Packit Service fb6fa5
         overlapping tags. */
Packit Service fb6fa5
      g_assert ( (toggled_on && seg->type == &gtk_text_toggle_off_type) ||
Packit Service fb6fa5
                 (!toggled_on && seg->type == &gtk_text_toggle_on_type) );
Packit Service fb6fa5
Packit Service fb6fa5
      toggled_on = !toggled_on;
Packit Service fb6fa5
Packit Service fb6fa5
#if 0
Packit Service fb6fa5
      printf ("deleting %s toggle\n",
Packit Service fb6fa5
              seg->type == &gtk_text_toggle_on_type ? "on" : "off");
Packit Service fb6fa5
#endif
Packit Service fb6fa5
      /* Remove toggle segment from the list. */
Packit Service fb6fa5
      if (prev == seg)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          line->segments = seg->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else
Packit Service fb6fa5
        {
Packit Service fb6fa5
          while (prev->next != seg)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              prev = prev->next;
Packit Service fb6fa5
            }
Packit Service fb6fa5
          prev->next = seg->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      /* Inform iterators we've hosed them. This actually reflects a
Packit Service fb6fa5
         bit of inefficiency; if you have the same tag toggled on and
Packit Service fb6fa5
         off a lot in a single line, we keep having the rescan from
Packit Service fb6fa5
         the front of the line. Of course we have to do that to get
Packit Service fb6fa5
         "prev" anyway, but here we are doing it an additional
Packit Service fb6fa5
         time. FIXME */
Packit Service fb6fa5
      segments_changed (tree);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Update node counts */
Packit Service fb6fa5
      if (seg->body.toggle.inNodeCounts)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          _gtk_change_node_toggle_count (line->parent,
Packit Service fb6fa5
                                         info, -1);
Packit Service fb6fa5
          seg->body.toggle.inNodeCounts = FALSE;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      g_free (seg);
Packit Service fb6fa5
Packit Service fb6fa5
      /* We only clean up lines when we're done with them, saves some
Packit Service fb6fa5
         gratuitous line-segment-traversals */
Packit Service fb6fa5
Packit Service fb6fa5
      if (cleanupline != line)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          cleanup_line (cleanupline);
Packit Service fb6fa5
          cleanupline = line;
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  iter_stack_free (stack);
Packit Service fb6fa5
Packit Service fb6fa5
  /* toggled_on now reflects the toggle state _just before_ the
Packit Service fb6fa5
     end iterator. The end iterator could already have a toggle
Packit Service fb6fa5
     on or a toggle off. */
Packit Service fb6fa5
  if ( (add && !toggled_on) ||
Packit Service fb6fa5
       (!add && toggled_on) )
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* This could create a second toggle at the start position;
Packit Service fb6fa5
         cleanup_line () will remove it if so. */
Packit Service fb6fa5
Packit Service fb6fa5
      seg = _gtk_toggle_segment_new (info, !add);
Packit Service fb6fa5
Packit Service fb6fa5
      prev = gtk_text_line_segment_split (&end;;
Packit Service fb6fa5
      if (prev == NULL)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          seg->next = end_line->segments;
Packit Service fb6fa5
          end_line->segments = seg;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else
Packit Service fb6fa5
        {
Packit Service fb6fa5
          seg->next = prev->next;
Packit Service fb6fa5
          prev->next = seg;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      /* cleanup_line adds the new toggle to the node counts. */
Packit Service fb6fa5
      g_assert (seg->body.toggle.inNodeCounts == FALSE);
Packit Service fb6fa5
#if 0
Packit Service fb6fa5
      printf ("added toggle at end\n");
Packit Service fb6fa5
#endif
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Cleanup cleanupline and the last line of the range, if
Packit Service fb6fa5
   * these are different.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  cleanup_line (cleanupline);
Packit Service fb6fa5
  if (cleanupline != end_line)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      cleanup_line (end_line);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  segments_changed (tree);
Packit Service fb6fa5
Packit Service fb6fa5
  queue_tag_redisplay (tree, tag, &start, &end;;
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit Service fb6fa5
    _gtk_text_btree_check (tree);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * "Getters"
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
static GtkTextLine*
Packit Service fb6fa5
get_line_internal (GtkTextBTree *tree,
Packit Service fb6fa5
                   gint          line_number,
Packit Service fb6fa5
                   gint         *real_line_number,
Packit Service fb6fa5
                   gboolean      include_last)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBTreeNode *node;
Packit Service fb6fa5
  GtkTextLine *line;
Packit Service fb6fa5
  int lines_left;
Packit Service fb6fa5
  int line_count;
Packit Service fb6fa5
Packit Service fb6fa5
  line_count = _gtk_text_btree_line_count (tree);
Packit Service fb6fa5
  if (!include_last)
Packit Service fb6fa5
    line_count -= 1;
Packit Service fb6fa5
  
Packit Service fb6fa5
  if (line_number < 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      line_number = line_count;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (line_number > line_count)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      line_number = line_count;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (real_line_number)
Packit Service fb6fa5
    *real_line_number = line_number;
Packit Service fb6fa5
Packit Service fb6fa5
  node = tree->root_node;
Packit Service fb6fa5
  lines_left = line_number;
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Work down through levels of the tree until a GtkTextBTreeNode is found at
Packit Service fb6fa5
   * level 0.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  while (node->level != 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      for (node = node->children.node;
Packit Service fb6fa5
           node->num_lines <= lines_left;
Packit Service fb6fa5
           node = node->next)
Packit Service fb6fa5
        {
Packit Service fb6fa5
#if 0
Packit Service fb6fa5
          if (node == NULL)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              g_error ("gtk_text_btree_find_line ran out of GtkTextBTreeNodes");
Packit Service fb6fa5
            }
Packit Service fb6fa5
#endif
Packit Service fb6fa5
          lines_left -= node->num_lines;
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Work through the lines attached to the level-0 GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  for (line = node->children.line; lines_left > 0;
Packit Service fb6fa5
       line = line->next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
#if 0
Packit Service fb6fa5
      if (line == NULL)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          g_error ("gtk_text_btree_find_line ran out of lines");
Packit Service fb6fa5
        }
Packit Service fb6fa5
#endif
Packit Service fb6fa5
      lines_left -= 1;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  return line;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextLine*
Packit Service fb6fa5
_gtk_text_btree_get_end_iter_line (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return
Packit Service fb6fa5
    _gtk_text_btree_get_line (tree,
Packit Service fb6fa5
                              _gtk_text_btree_line_count (tree) - 1,
Packit Service fb6fa5
                              NULL);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextLine*
Packit Service fb6fa5
_gtk_text_btree_get_line (GtkTextBTree *tree,
Packit Service fb6fa5
                          gint          line_number,
Packit Service fb6fa5
                          gint         *real_line_number)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return get_line_internal (tree, line_number, real_line_number, TRUE);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextLine*
Packit Service fb6fa5
_gtk_text_btree_get_line_no_last (GtkTextBTree      *tree,
Packit Service fb6fa5
                                  gint               line_number,
Packit Service fb6fa5
                                  gint              *real_line_number)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return get_line_internal (tree, line_number, real_line_number, FALSE);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextLine*
Packit Service fb6fa5
_gtk_text_btree_get_line_at_char (GtkTextBTree      *tree,
Packit Service fb6fa5
                                  gint               char_index,
Packit Service fb6fa5
                                  gint              *line_start_index,
Packit Service fb6fa5
                                  gint              *real_char_index)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBTreeNode *node;
Packit Service fb6fa5
  GtkTextLine *line;
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  int chars_left;
Packit Service fb6fa5
  int chars_in_line;
Packit Service fb6fa5
Packit Service fb6fa5
  node = tree->root_node;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Clamp to valid indexes (-1 is magic for "highest index"),
Packit Service fb6fa5
   * node->num_chars includes the two newlines that aren't really
Packit Service fb6fa5
   * in the buffer.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  if (char_index < 0 || char_index >= (node->num_chars - 1))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      char_index = node->num_chars - 2;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  *real_char_index = char_index;
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Work down through levels of the tree until a GtkTextBTreeNode is found at
Packit Service fb6fa5
   * level 0.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  chars_left = char_index;
Packit Service fb6fa5
  while (node->level != 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      for (node = node->children.node;
Packit Service fb6fa5
           chars_left >= node->num_chars;
Packit Service fb6fa5
           node = node->next)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          chars_left -= node->num_chars;
Packit Service fb6fa5
Packit Service fb6fa5
          g_assert (chars_left >= 0);
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (chars_left == 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* Start of a line */
Packit Service fb6fa5
Packit Service fb6fa5
      *line_start_index = char_index;
Packit Service fb6fa5
      return node->children.line;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Work through the lines attached to the level-0 GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  chars_in_line = 0;
Packit Service fb6fa5
  seg = NULL;
Packit Service fb6fa5
  for (line = node->children.line; line != NULL; line = line->next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      seg = line->segments;
Packit Service fb6fa5
      while (seg != NULL)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          if (chars_in_line + seg->char_count > chars_left)
Packit Service fb6fa5
            goto found; /* found our line/segment */
Packit Service fb6fa5
Packit Service fb6fa5
          chars_in_line += seg->char_count;
Packit Service fb6fa5
Packit Service fb6fa5
          seg = seg->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      chars_left -= chars_in_line;
Packit Service fb6fa5
Packit Service fb6fa5
      chars_in_line = 0;
Packit Service fb6fa5
      seg = NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
 found:
Packit Service fb6fa5
Packit Service fb6fa5
  g_assert (line != NULL); /* hosage, ran out of lines */
Packit Service fb6fa5
  g_assert (seg != NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  *line_start_index = char_index - chars_left;
Packit Service fb6fa5
  return line;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/* It returns an array sorted by tags priority, ready to pass to
Packit Service fb6fa5
 * _gtk_text_attributes_fill_from_tags() */
Packit Service fb6fa5
GtkTextTag**
Packit Service fb6fa5
_gtk_text_btree_get_tags (const GtkTextIter *iter,
Packit Service fb6fa5
                         gint *num_tags)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBTreeNode *node;
Packit Service fb6fa5
  GtkTextLine *siblingline;
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  int src, dst, index;
Packit Service fb6fa5
  TagInfo tagInfo;
Packit Service fb6fa5
  GtkTextLine *line;
Packit Service fb6fa5
  gint byte_index;
Packit Service fb6fa5
Packit Service fb6fa5
#define NUM_TAG_INFOS 10
Packit Service fb6fa5
Packit Service fb6fa5
  line = _gtk_text_iter_get_text_line (iter);
Packit Service fb6fa5
  byte_index = gtk_text_iter_get_line_index (iter);
Packit Service fb6fa5
Packit Service fb6fa5
  tagInfo.numTags = 0;
Packit Service fb6fa5
  tagInfo.arraySize = NUM_TAG_INFOS;
Packit Service fb6fa5
  tagInfo.tags = g_new (GtkTextTag*, NUM_TAG_INFOS);
Packit Service fb6fa5
  tagInfo.counts = g_new (int, NUM_TAG_INFOS);
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Record tag toggles within the line of indexPtr but preceding
Packit Service fb6fa5
   * indexPtr. Note that if this loop segfaults, your
Packit Service fb6fa5
   * byte_index probably points past the sum of all
Packit Service fb6fa5
   * seg->byte_count */
Packit Service fb6fa5
Packit Service fb6fa5
  for (index = 0, seg = line->segments;
Packit Service fb6fa5
       (index + seg->byte_count) <= byte_index;
Packit Service fb6fa5
       index += seg->byte_count, seg = seg->next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if ((seg->type == &gtk_text_toggle_on_type)
Packit Service fb6fa5
          || (seg->type == &gtk_text_toggle_off_type))
Packit Service fb6fa5
        {
Packit Service fb6fa5
          inc_count (seg->body.toggle.info->tag, 1, &tagInfo);
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Record toggles for tags in lines that are predecessors of
Packit Service fb6fa5
   * line but under the same level-0 GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  for (siblingline = line->parent->children.line;
Packit Service fb6fa5
       siblingline != line;
Packit Service fb6fa5
       siblingline = siblingline->next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      for (seg = siblingline->segments; seg != NULL;
Packit Service fb6fa5
           seg = seg->next)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          if ((seg->type == &gtk_text_toggle_on_type)
Packit Service fb6fa5
              || (seg->type == &gtk_text_toggle_off_type))
Packit Service fb6fa5
            {
Packit Service fb6fa5
              inc_count (seg->body.toggle.info->tag, 1, &tagInfo);
Packit Service fb6fa5
            }
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * For each GtkTextBTreeNode in the ancestry of this line, record tag
Packit Service fb6fa5
   * toggles for all siblings that precede that GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  for (node = line->parent; node->parent != NULL;
Packit Service fb6fa5
       node = node->parent)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkTextBTreeNode *siblingPtr;
Packit Service fb6fa5
      Summary *summary;
Packit Service fb6fa5
Packit Service fb6fa5
      for (siblingPtr = node->parent->children.node;
Packit Service fb6fa5
           siblingPtr != node; siblingPtr = siblingPtr->next)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          for (summary = siblingPtr->summary; summary != NULL;
Packit Service fb6fa5
               summary = summary->next)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              if (summary->toggle_count & 1)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  inc_count (summary->info->tag, summary->toggle_count,
Packit Service fb6fa5
                             &tagInfo);
Packit Service fb6fa5
                }
Packit Service fb6fa5
            }
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Go through the tag information and squash out all of the tags
Packit Service fb6fa5
   * that have even toggle counts (these tags exist before the point
Packit Service fb6fa5
   * of interest, but not at the desired character itself).
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  for (src = 0, dst = 0; src < tagInfo.numTags; src++)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (tagInfo.counts[src] & 1)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          g_assert (GTK_IS_TEXT_TAG (tagInfo.tags[src]));
Packit Service fb6fa5
          tagInfo.tags[dst] = tagInfo.tags[src];
Packit Service fb6fa5
          dst++;
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  *num_tags = dst;
Packit Service fb6fa5
  g_free (tagInfo.counts);
Packit Service fb6fa5
  if (dst == 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_free (tagInfo.tags);
Packit Service fb6fa5
      return NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* Sort tags in ascending order of priority */
Packit Service fb6fa5
  _gtk_text_tag_array_sort (tagInfo.tags, dst);
Packit Service fb6fa5
Packit Service fb6fa5
  return tagInfo.tags;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
copy_segment (GString *string,
Packit Service fb6fa5
              gboolean include_hidden,
Packit Service fb6fa5
              gboolean include_nonchars,
Packit Service fb6fa5
              const GtkTextIter *start,
Packit Service fb6fa5
              const GtkTextIter *end)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *end_seg;
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_text_iter_equal (start, end))
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  seg = _gtk_text_iter_get_indexable_segment (start);
Packit Service fb6fa5
  end_seg = _gtk_text_iter_get_indexable_segment (end);
Packit Service fb6fa5
Packit Service fb6fa5
  if (seg->type == &gtk_text_char_type)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gboolean copy = TRUE;
Packit Service fb6fa5
      gint copy_bytes = 0;
Packit Service fb6fa5
      gint copy_start = 0;
Packit Service fb6fa5
Packit Service fb6fa5
      /* Don't copy if we're invisible; segments are invisible/not
Packit Service fb6fa5
         as a whole, no need to check each char */
Packit Service fb6fa5
      if (!include_hidden &&
Packit Service fb6fa5
          _gtk_text_btree_char_is_invisible (start))
Packit Service fb6fa5
        {
Packit Service fb6fa5
          copy = FALSE;
Packit Service fb6fa5
          /* printf (" <invisible>\n"); */
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      copy_start = _gtk_text_iter_get_segment_byte (start);
Packit Service fb6fa5
Packit Service fb6fa5
      if (seg == end_seg)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          /* End is in the same segment; need to copy fewer bytes. */
Packit Service fb6fa5
          gint end_byte = _gtk_text_iter_get_segment_byte (end);
Packit Service fb6fa5
Packit Service fb6fa5
          copy_bytes = end_byte - copy_start;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else
Packit Service fb6fa5
        copy_bytes = seg->byte_count - copy_start;
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (copy_bytes != 0); /* Due to iter equality check at
Packit Service fb6fa5
                                     front of this function. */
Packit Service fb6fa5
Packit Service fb6fa5
      if (copy)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          g_assert ((copy_start + copy_bytes) <= seg->byte_count);
Packit Service fb6fa5
Packit Service fb6fa5
          g_string_append_len (string,
Packit Service fb6fa5
                               seg->body.chars + copy_start,
Packit Service fb6fa5
                               copy_bytes);
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      /* printf ("  :%s\n", string->str); */
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (seg->type == &gtk_text_pixbuf_type ||
Packit Service fb6fa5
           seg->type == &gtk_text_child_type)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gboolean copy = TRUE;
Packit Service fb6fa5
Packit Service fb6fa5
      if (!include_nonchars)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          copy = FALSE;
Packit Service fb6fa5
        }
Packit Service fb6fa5
      else if (!include_hidden &&
Packit Service fb6fa5
               _gtk_text_btree_char_is_invisible (start))
Packit Service fb6fa5
        {
Packit Service fb6fa5
          copy = FALSE;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      if (copy)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          g_string_append_len (string,
Packit Service fb6fa5
                               gtk_text_unknown_char_utf8,
Packit Service fb6fa5
                               3);
Packit Service fb6fa5
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
gchar*
Packit Service fb6fa5
_gtk_text_btree_get_text (const GtkTextIter *start_orig,
Packit Service fb6fa5
                         const GtkTextIter *end_orig,
Packit Service fb6fa5
                         gboolean include_hidden,
Packit Service fb6fa5
                         gboolean include_nonchars)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  GtkTextLineSegment *end_seg;
Packit Service fb6fa5
  GString *retval;
Packit Service fb6fa5
  gchar *str;
Packit Service fb6fa5
  GtkTextIter iter;
Packit Service fb6fa5
  GtkTextIter start;
Packit Service fb6fa5
  GtkTextIter end;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (start_orig != NULL, NULL);
Packit Service fb6fa5
  g_return_val_if_fail (end_orig != NULL, NULL);
Packit Service fb6fa5
  g_return_val_if_fail (_gtk_text_iter_get_btree (start_orig) ==
Packit Service fb6fa5
                        _gtk_text_iter_get_btree (end_orig), NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  start = *start_orig;
Packit Service fb6fa5
  end = *end_orig;
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_text_iter_order (&start, &end;;
Packit Service fb6fa5
Packit Service fb6fa5
  retval = g_string_new (NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  end_seg = _gtk_text_iter_get_indexable_segment (&end;;
Packit Service fb6fa5
  iter = start;
Packit Service fb6fa5
  seg = _gtk_text_iter_get_indexable_segment (&iter);
Packit Service fb6fa5
  while (seg != end_seg)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      copy_segment (retval, include_hidden, include_nonchars,
Packit Service fb6fa5
                    &iter, &end;;
Packit Service fb6fa5
Packit Service fb6fa5
      _gtk_text_iter_forward_indexable_segment (&iter);
Packit Service fb6fa5
Packit Service fb6fa5
      seg = _gtk_text_iter_get_indexable_segment (&iter);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  copy_segment (retval, include_hidden, include_nonchars, &iter, &end;;
Packit Service fb6fa5
Packit Service fb6fa5
  str = retval->str;
Packit Service fb6fa5
  g_string_free (retval, FALSE);
Packit Service fb6fa5
  return str;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
gint
Packit Service fb6fa5
_gtk_text_btree_line_count (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  /* Subtract bogus line at the end; we return a count
Packit Service fb6fa5
     of usable lines. */
Packit Service fb6fa5
  return tree->root_node->num_lines - 1;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
gint
Packit Service fb6fa5
_gtk_text_btree_char_count (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  /* Exclude newline in bogus last line and the
Packit Service fb6fa5
   * one in the last line that is after the end iterator
Packit Service fb6fa5
   */
Packit Service fb6fa5
  return tree->root_node->num_chars - 2;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
#define LOTSA_TAGS 1000
Packit Service fb6fa5
gboolean
Packit Service fb6fa5
_gtk_text_btree_char_is_invisible (const GtkTextIter *iter)
Packit Service fb6fa5
{
Packit Service fb6fa5
  gboolean invisible = FALSE;  /* if nobody says otherwise, it's visible */
Packit Service fb6fa5
Packit Service fb6fa5
  int deftagCnts[LOTSA_TAGS] = { 0, };
Packit Service fb6fa5
  int *tagCnts = deftagCnts;
Packit Service fb6fa5
  GtkTextTag *deftags[LOTSA_TAGS];
Packit Service fb6fa5
  GtkTextTag **tags = deftags;
Packit Service fb6fa5
  int numTags;
Packit Service fb6fa5
  GtkTextBTreeNode *node;
Packit Service fb6fa5
  GtkTextLine *siblingline;
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  GtkTextTag *tag;
Packit Service fb6fa5
  int i, index;
Packit Service fb6fa5
  GtkTextLine *line;
Packit Service fb6fa5
  GtkTextBTree *tree;
Packit Service fb6fa5
  gint byte_index;
Packit Service fb6fa5
Packit Service fb6fa5
  line = _gtk_text_iter_get_text_line (iter);
Packit Service fb6fa5
  tree = _gtk_text_iter_get_btree (iter);
Packit Service fb6fa5
  byte_index = gtk_text_iter_get_line_index (iter);
Packit Service fb6fa5
Packit Service fb6fa5
  numTags = gtk_text_tag_table_get_size (tree->table);
Packit Service fb6fa5
Packit Service fb6fa5
  /* almost always avoid malloc, so stay out of system calls */
Packit Service fb6fa5
  if (LOTSA_TAGS < numTags)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      tagCnts = g_new0 (int, numTags);
Packit Service fb6fa5
      tags = g_new (GtkTextTag*, numTags);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Record tag toggles within the line of indexPtr but preceding
Packit Service fb6fa5
   * indexPtr.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  for (index = 0, seg = line->segments;
Packit Service fb6fa5
       (index + seg->byte_count) <= byte_index; /* segfault here means invalid index */
Packit Service fb6fa5
       index += seg->byte_count, seg = seg->next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if ((seg->type == &gtk_text_toggle_on_type)
Packit Service fb6fa5
          || (seg->type == &gtk_text_toggle_off_type))
Packit Service fb6fa5
        {
Packit Service fb6fa5
          tag = seg->body.toggle.info->tag;
Packit Service fb6fa5
          if (tag->invisible_set)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              tags[tag->priority] = tag;
Packit Service fb6fa5
              tagCnts[tag->priority]++;
Packit Service fb6fa5
            }
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Record toggles for tags in lines that are predecessors of
Packit Service fb6fa5
   * line but under the same level-0 GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  for (siblingline = line->parent->children.line;
Packit Service fb6fa5
       siblingline != line;
Packit Service fb6fa5
       siblingline = siblingline->next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      for (seg = siblingline->segments; seg != NULL;
Packit Service fb6fa5
           seg = seg->next)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          if ((seg->type == &gtk_text_toggle_on_type)
Packit Service fb6fa5
              || (seg->type == &gtk_text_toggle_off_type))
Packit Service fb6fa5
            {
Packit Service fb6fa5
              tag = seg->body.toggle.info->tag;
Packit Service fb6fa5
              if (tag->invisible_set)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  tags[tag->priority] = tag;
Packit Service fb6fa5
                  tagCnts[tag->priority]++;
Packit Service fb6fa5
                }
Packit Service fb6fa5
            }
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * For each GtkTextBTreeNode in the ancestry of this line, record tag toggles
Packit Service fb6fa5
   * for all siblings that precede that GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  for (node = line->parent; node->parent != NULL;
Packit Service fb6fa5
       node = node->parent)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkTextBTreeNode *siblingPtr;
Packit Service fb6fa5
      Summary *summary;
Packit Service fb6fa5
Packit Service fb6fa5
      for (siblingPtr = node->parent->children.node;
Packit Service fb6fa5
           siblingPtr != node; siblingPtr = siblingPtr->next)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          for (summary = siblingPtr->summary; summary != NULL;
Packit Service fb6fa5
               summary = summary->next)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              if (summary->toggle_count & 1)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  tag = summary->info->tag;
Packit Service fb6fa5
                  if (tag->invisible_set)
Packit Service fb6fa5
                    {
Packit Service fb6fa5
                      tags[tag->priority] = tag;
Packit Service fb6fa5
                      tagCnts[tag->priority] += summary->toggle_count;
Packit Service fb6fa5
                    }
Packit Service fb6fa5
                }
Packit Service fb6fa5
            }
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Now traverse from highest priority to lowest,
Packit Service fb6fa5
   * take invisible value from first odd count (= on)
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  for (i = numTags-1; i >=0; i--)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (tagCnts[i] & 1)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          /* FIXME not sure this should be if 0 */
Packit Service fb6fa5
#if 0
Packit Service fb6fa5
#ifndef ALWAYS_SHOW_SELECTION
Packit Service fb6fa5
          /* who would make the selection invisible? */
Packit Service fb6fa5
          if ((tag == tkxt->seltag)
Packit Service fb6fa5
              && !(tkxt->flags & GOT_FOCUS))
Packit Service fb6fa5
            {
Packit Service fb6fa5
              continue;
Packit Service fb6fa5
            }
Packit Service fb6fa5
#endif
Packit Service fb6fa5
#endif
Packit Service fb6fa5
          invisible = tags[i]->values->invisible;
Packit Service fb6fa5
          break;
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (LOTSA_TAGS < numTags)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_free (tagCnts);
Packit Service fb6fa5
      g_free (tags);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return invisible;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Manipulate marks
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
redisplay_region (GtkTextBTree      *tree,
Packit Service fb6fa5
                  const GtkTextIter *start,
Packit Service fb6fa5
                  const GtkTextIter *end,
Packit Service fb6fa5
                  gboolean           cursors_only)
Packit Service fb6fa5
{
Packit Service fb6fa5
  BTreeView *view;
Packit Service fb6fa5
  GtkTextLine *start_line, *end_line;
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_text_iter_compare (start, end) > 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      const GtkTextIter *tmp = start;
Packit Service fb6fa5
      start = end;
Packit Service fb6fa5
      end = tmp;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  start_line = _gtk_text_iter_get_text_line (start);
Packit Service fb6fa5
  end_line = _gtk_text_iter_get_text_line (end);
Packit Service fb6fa5
Packit Service fb6fa5
  view = tree->views;
Packit Service fb6fa5
  while (view != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gint start_y, end_y;
Packit Service fb6fa5
      GtkTextLineData *ld;
Packit Service fb6fa5
Packit Service fb6fa5
      start_y = _gtk_text_btree_find_line_top (tree, start_line, view->view_id);
Packit Service fb6fa5
Packit Service fb6fa5
      if (end_line == start_line)
Packit Service fb6fa5
        end_y = start_y;
Packit Service fb6fa5
      else
Packit Service fb6fa5
        end_y = _gtk_text_btree_find_line_top (tree, end_line, view->view_id);
Packit Service fb6fa5
Packit Service fb6fa5
      ld = _gtk_text_line_get_data (end_line, view->view_id);
Packit Service fb6fa5
      if (ld)
Packit Service fb6fa5
        end_y += ld->height;
Packit Service fb6fa5
Packit Service fb6fa5
      if (cursors_only)
Packit Service fb6fa5
	gtk_text_layout_cursors_changed (view->layout, start_y,
Packit Service fb6fa5
					 end_y - start_y,
Packit Service fb6fa5
					  end_y - start_y);
Packit Service fb6fa5
      else
Packit Service fb6fa5
	gtk_text_layout_changed (view->layout, start_y,
Packit Service fb6fa5
				 end_y - start_y,
Packit Service fb6fa5
				 end_y - start_y);
Packit Service fb6fa5
Packit Service fb6fa5
      view = view->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
redisplay_mark (GtkTextLineSegment *mark)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextIter iter;
Packit Service fb6fa5
  GtkTextIter end;
Packit Service fb6fa5
  gboolean cursor_only;
Packit Service fb6fa5
Packit Service fb6fa5
  _gtk_text_btree_get_iter_at_mark (mark->body.mark.tree,
Packit Service fb6fa5
                                   &iter,
Packit Service fb6fa5
                                   mark->body.mark.obj);
Packit Service fb6fa5
Packit Service fb6fa5
  end = iter;
Packit Service fb6fa5
  gtk_text_iter_forward_char (&end;;
Packit Service fb6fa5
Packit Service fb6fa5
  DV (g_print ("invalidating due to moving visible mark (%s)\n", G_STRLOC));
Packit Service fb6fa5
  cursor_only = mark == mark->body.mark.tree->insert_mark->segment;
Packit Service fb6fa5
  _gtk_text_btree_invalidate_region (mark->body.mark.tree, &iter, &end, cursor_only);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
redisplay_mark_if_visible (GtkTextLineSegment *mark)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (!mark->body.mark.visible)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
  else
Packit Service fb6fa5
    redisplay_mark (mark);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
ensure_not_off_end (GtkTextBTree *tree,
Packit Service fb6fa5
                    GtkTextLineSegment *mark,
Packit Service fb6fa5
                    GtkTextIter *iter)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (gtk_text_iter_get_line (iter) == _gtk_text_btree_line_count (tree))
Packit Service fb6fa5
    gtk_text_iter_backward_char (iter);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static GtkTextLineSegment*
Packit Service fb6fa5
real_set_mark (GtkTextBTree      *tree,
Packit Service fb6fa5
               GtkTextMark       *existing_mark,
Packit Service fb6fa5
               const gchar       *name,
Packit Service fb6fa5
               gboolean           left_gravity,
Packit Service fb6fa5
               const GtkTextIter *where,
Packit Service fb6fa5
               gboolean           should_exist,
Packit Service fb6fa5
               gboolean           redraw_selections)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *mark;
Packit Service fb6fa5
  GtkTextIter iter;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (tree != NULL, NULL);
Packit Service fb6fa5
  g_return_val_if_fail (where != NULL, NULL);
Packit Service fb6fa5
  g_return_val_if_fail (_gtk_text_iter_get_btree (where) == tree, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  if (existing_mark)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (gtk_text_mark_get_buffer (existing_mark) != NULL)
Packit Service fb6fa5
	mark = existing_mark->segment;
Packit Service fb6fa5
      else
Packit Service fb6fa5
	mark = NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (name != NULL)
Packit Service fb6fa5
    mark = g_hash_table_lookup (tree->mark_table,
Packit Service fb6fa5
                                name);
Packit Service fb6fa5
  else
Packit Service fb6fa5
    mark = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  if (should_exist && mark == NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_warning ("No mark `%s' exists!", name);
Packit Service fb6fa5
      return NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* OK if !should_exist and it does already exist, in that case
Packit Service fb6fa5
   * we just move it.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  
Packit Service fb6fa5
  iter = *where;
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit Service fb6fa5
    _gtk_text_iter_check (&iter);
Packit Service fb6fa5
  
Packit Service fb6fa5
  if (mark != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (redraw_selections &&
Packit Service fb6fa5
          (mark == tree->insert_mark->segment ||
Packit Service fb6fa5
           mark == tree->selection_bound_mark->segment))
Packit Service fb6fa5
        {
Packit Service fb6fa5
          GtkTextIter old_pos;
Packit Service fb6fa5
Packit Service fb6fa5
          _gtk_text_btree_get_iter_at_mark (tree, &old_pos,
Packit Service fb6fa5
                                           mark->body.mark.obj);
Packit Service fb6fa5
          redisplay_region (tree, &old_pos, where, TRUE);
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      /*
Packit Service fb6fa5
       * don't let visible marks be after the final newline of the
Packit Service fb6fa5
       *  file.
Packit Service fb6fa5
       */
Packit Service fb6fa5
Packit Service fb6fa5
      if (mark->body.mark.visible)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          ensure_not_off_end (tree, mark, &iter);
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      /* Redraw the mark's old location. */
Packit Service fb6fa5
      redisplay_mark_if_visible (mark);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Unlink mark from its current location.
Packit Service fb6fa5
         This could hose our iterator... */
Packit Service fb6fa5
      gtk_text_btree_unlink_segment (tree, mark,
Packit Service fb6fa5
                                     mark->body.mark.line);
Packit Service fb6fa5
      mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
Packit Service fb6fa5
      g_assert (mark->body.mark.line == _gtk_text_iter_get_text_line (&iter));
Packit Service fb6fa5
Packit Service fb6fa5
      segments_changed (tree); /* make sure the iterator recomputes its
Packit Service fb6fa5
                                  segment */
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (existing_mark)
Packit Service fb6fa5
	g_object_ref (existing_mark);
Packit Service fb6fa5
      else
Packit Service fb6fa5
	existing_mark = gtk_text_mark_new (name, left_gravity);
Packit Service fb6fa5
Packit Service fb6fa5
      mark = existing_mark->segment;
Packit Service fb6fa5
      _gtk_mark_segment_set_tree (mark, tree);
Packit Service fb6fa5
Packit Service fb6fa5
      mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
Packit Service fb6fa5
Packit Service fb6fa5
      if (mark->body.mark.name)
Packit Service fb6fa5
        g_hash_table_insert (tree->mark_table,
Packit Service fb6fa5
                             mark->body.mark.name,
Packit Service fb6fa5
                             mark);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit Service fb6fa5
    _gtk_text_iter_check (&iter);
Packit Service fb6fa5
  
Packit Service fb6fa5
  /* Link mark into new location */
Packit Service fb6fa5
  gtk_text_btree_link_segment (mark, &iter);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Invalidate some iterators. */
Packit Service fb6fa5
  segments_changed (tree);
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * update the screen at the mark's new location.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  redisplay_mark_if_visible (mark);
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit Service fb6fa5
    _gtk_text_iter_check (&iter);
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit Service fb6fa5
    _gtk_text_btree_check (tree);
Packit Service fb6fa5
  
Packit Service fb6fa5
  return mark;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextMark*
Packit Service fb6fa5
_gtk_text_btree_set_mark (GtkTextBTree *tree,
Packit Service fb6fa5
                         GtkTextMark  *existing_mark,
Packit Service fb6fa5
                         const gchar *name,
Packit Service fb6fa5
                         gboolean left_gravity,
Packit Service fb6fa5
                         const GtkTextIter *iter,
Packit Service fb6fa5
                         gboolean should_exist)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
Packit Service fb6fa5
  seg = real_set_mark (tree, existing_mark,
Packit Service fb6fa5
                       name, left_gravity, iter, should_exist,
Packit Service fb6fa5
                       TRUE);
Packit Service fb6fa5
Packit Service fb6fa5
  return seg ? seg->body.mark.obj : NULL;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
gboolean
Packit Service fb6fa5
_gtk_text_btree_get_selection_bounds (GtkTextBTree *tree,
Packit Service fb6fa5
                                     GtkTextIter  *start,
Packit Service fb6fa5
                                     GtkTextIter  *end)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextIter tmp_start, tmp_end;
Packit Service fb6fa5
Packit Service fb6fa5
  _gtk_text_btree_get_iter_at_mark (tree, &tmp_start,
Packit Service fb6fa5
                                   tree->insert_mark);
Packit Service fb6fa5
  _gtk_text_btree_get_iter_at_mark (tree, &tmp_end,
Packit Service fb6fa5
                                   tree->selection_bound_mark);
Packit Service fb6fa5
Packit Service fb6fa5
  if (gtk_text_iter_equal (&tmp_start, &tmp_end))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (start)
Packit Service fb6fa5
        *start = tmp_start;
Packit Service fb6fa5
Packit Service fb6fa5
      if (end)
Packit Service fb6fa5
        *end = tmp_end;
Packit Service fb6fa5
Packit Service fb6fa5
      return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gtk_text_iter_order (&tmp_start, &tmp_end);
Packit Service fb6fa5
Packit Service fb6fa5
      if (start)
Packit Service fb6fa5
        *start = tmp_start;
Packit Service fb6fa5
Packit Service fb6fa5
      if (end)
Packit Service fb6fa5
        *end = tmp_end;
Packit Service fb6fa5
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_place_cursor (GtkTextBTree      *tree,
Packit Service fb6fa5
                             const GtkTextIter *iter)
Packit Service fb6fa5
{
Packit Service fb6fa5
  _gtk_text_btree_select_range (tree, iter, iter);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_select_range (GtkTextBTree      *tree,
Packit Service fb6fa5
			      const GtkTextIter *ins,
Packit Service fb6fa5
                              const GtkTextIter *bound)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextIter old_ins, old_bound;
Packit Service fb6fa5
Packit Service fb6fa5
  _gtk_text_btree_get_iter_at_mark (tree, &old_ins,
Packit Service fb6fa5
                                    tree->insert_mark);
Packit Service fb6fa5
  _gtk_text_btree_get_iter_at_mark (tree, &old_bound,
Packit Service fb6fa5
                                    tree->selection_bound_mark);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Check if it's no-op since gtk_text_buffer_place_cursor()
Packit Service fb6fa5
   * also calls this, and this will redraw the cursor line. */
Packit Service fb6fa5
  if (!gtk_text_iter_equal (&old_ins, ins) ||
Packit Service fb6fa5
      !gtk_text_iter_equal (&old_bound, bound))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      redisplay_region (tree, &old_ins, &old_bound, TRUE);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Move insert AND selection_bound before we redisplay */
Packit Service fb6fa5
      real_set_mark (tree, tree->insert_mark,
Packit Service fb6fa5
		     "insert", FALSE, ins, TRUE, FALSE);
Packit Service fb6fa5
      real_set_mark (tree, tree->selection_bound_mark,
Packit Service fb6fa5
		     "selection_bound", FALSE, bound, TRUE, FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
      redisplay_region (tree, ins, bound, TRUE);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_remove_mark_by_name (GtkTextBTree *tree,
Packit Service fb6fa5
                                    const gchar *name)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextMark *mark;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (tree != NULL);
Packit Service fb6fa5
  g_return_if_fail (name != NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  mark = g_hash_table_lookup (tree->mark_table,
Packit Service fb6fa5
                              name);
Packit Service fb6fa5
Packit Service fb6fa5
  _gtk_text_btree_remove_mark (tree, mark);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_release_mark_segment (GtkTextBTree       *tree,
Packit Service fb6fa5
                                      GtkTextLineSegment *segment)
Packit Service fb6fa5
{
Packit Service fb6fa5
Packit Service fb6fa5
  if (segment->body.mark.name)
Packit Service fb6fa5
    g_hash_table_remove (tree->mark_table, segment->body.mark.name);
Packit Service fb6fa5
Packit Service fb6fa5
  segment->body.mark.tree = NULL;
Packit Service fb6fa5
  segment->body.mark.line = NULL;
Packit Service fb6fa5
  
Packit Service fb6fa5
  /* Remove the ref on the mark, which frees segment as a side effect
Packit Service fb6fa5
   * if this is the last reference.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  g_object_unref (segment->body.mark.obj);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
void
Packit Service fb6fa5
_gtk_text_btree_remove_mark (GtkTextBTree *tree,
Packit Service fb6fa5
                             GtkTextMark *mark)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *segment;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (mark != NULL);
Packit Service fb6fa5
  g_return_if_fail (tree != NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  segment = mark->segment;
Packit Service fb6fa5
Packit Service fb6fa5
  if (segment->body.mark.not_deleteable)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_warning ("Can't delete special mark `%s'", segment->body.mark.name);
Packit Service fb6fa5
      return;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* This calls cleanup_line and segments_changed */
Packit Service fb6fa5
  gtk_text_btree_unlink_segment (tree, segment, segment->body.mark.line);
Packit Service fb6fa5
  
Packit Service fb6fa5
  _gtk_text_btree_release_mark_segment (tree, segment);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
gboolean
Packit Service fb6fa5
_gtk_text_btree_mark_is_insert (GtkTextBTree *tree,
Packit Service fb6fa5
                                GtkTextMark *segment)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return segment == tree->insert_mark;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
gboolean
Packit Service fb6fa5
_gtk_text_btree_mark_is_selection_bound (GtkTextBTree *tree,
Packit Service fb6fa5
                                         GtkTextMark *segment)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return segment == tree->selection_bound_mark;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextMark *
Packit Service fb6fa5
_gtk_text_btree_get_insert (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return tree->insert_mark;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextMark *
Packit Service fb6fa5
_gtk_text_btree_get_selection_bound (GtkTextBTree *tree)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return tree->selection_bound_mark;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextMark*
Packit Service fb6fa5
_gtk_text_btree_get_mark_by_name (GtkTextBTree *tree,
Packit Service fb6fa5
                                  const gchar *name)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (tree != NULL, NULL);
Packit Service fb6fa5
  g_return_val_if_fail (name != NULL, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  seg = g_hash_table_lookup (tree->mark_table, name);
Packit Service fb6fa5
Packit Service fb6fa5
  return seg ? seg->body.mark.obj : NULL;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/**
Packit Service fb6fa5
 * gtk_text_mark_set_visible:
Packit Service fb6fa5
 * @mark: a #GtkTextMark
Packit Service fb6fa5
 * @setting: visibility of mark
Packit Service fb6fa5
 * 
Packit Service fb6fa5
 * Sets the visibility of @mark; the insertion point is normally
Packit Service fb6fa5
 * visible, i.e. you can see it as a vertical bar. Also, the text
Packit Service fb6fa5
 * widget uses a visible mark to indicate where a drop will occur when
Packit Service fb6fa5
 * dragging-and-dropping text. Most other marks are not visible.
Packit Service fb6fa5
 * Marks are not visible by default.
Packit Service fb6fa5
 * 
Packit Service fb6fa5
 **/
Packit Service fb6fa5
void
Packit Service fb6fa5
gtk_text_mark_set_visible (GtkTextMark       *mark,
Packit Service fb6fa5
                           gboolean           setting)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_if_fail (mark != NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  seg = mark->segment;
Packit Service fb6fa5
Packit Service fb6fa5
  if (seg->body.mark.visible == setting)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      seg->body.mark.visible = setting;
Packit Service fb6fa5
Packit Service fb6fa5
      if (seg->body.mark.tree)
Packit Service fb6fa5
	redisplay_mark (seg);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextLine*
Packit Service fb6fa5
_gtk_text_btree_first_could_contain_tag (GtkTextBTree *tree,
Packit Service fb6fa5
                                        GtkTextTag *tag)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBTreeNode *node;
Packit Service fb6fa5
  GtkTextTagInfo *info;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (tree != NULL, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  if (tag != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      info = gtk_text_btree_get_existing_tag_info (tree, tag);
Packit Service fb6fa5
Packit Service fb6fa5
      if (info == NULL)
Packit Service fb6fa5
        return NULL;
Packit Service fb6fa5
Packit Service fb6fa5
      if (info->tag_root == NULL)
Packit Service fb6fa5
        return NULL;
Packit Service fb6fa5
Packit Service fb6fa5
      node = info->tag_root;
Packit Service fb6fa5
Packit Service fb6fa5
      /* We know the tag root has instances of the given
Packit Service fb6fa5
         tag below it */
Packit Service fb6fa5
Packit Service fb6fa5
    continue_outer_loop:
Packit Service fb6fa5
      g_assert (node != NULL);
Packit Service fb6fa5
      while (node->level > 0)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          g_assert (node != NULL); /* Failure probably means bad tag summaries. */
Packit Service fb6fa5
          node = node->children.node;
Packit Service fb6fa5
          while (node != NULL)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              if (gtk_text_btree_node_has_tag (node, tag))
Packit Service fb6fa5
                goto continue_outer_loop;
Packit Service fb6fa5
Packit Service fb6fa5
              node = node->next;
Packit Service fb6fa5
            }
Packit Service fb6fa5
          g_assert (node != NULL);
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (node != NULL); /* The tag summaries said some node had
Packit Service fb6fa5
                                  tag toggles... */
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (node->level == 0);
Packit Service fb6fa5
Packit Service fb6fa5
      return node->children.line;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* Looking for any tag at all (tag == NULL).
Packit Service fb6fa5
         Unfortunately this can't be done in a simple and efficient way
Packit Service fb6fa5
         right now; so I'm just going to return the
Packit Service fb6fa5
         first line in the btree. FIXME */
Packit Service fb6fa5
      return _gtk_text_btree_get_line (tree, 0, NULL);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkTextLine*
Packit Service fb6fa5
_gtk_text_btree_last_could_contain_tag (GtkTextBTree *tree,
Packit Service fb6fa5
                                       GtkTextTag *tag)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBTreeNode *node;
Packit Service fb6fa5
  GtkTextBTreeNode *last_node;
Packit Service fb6fa5
  GtkTextLine *line;
Packit Service fb6fa5
  GtkTextTagInfo *info;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (tree != NULL, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  if (tag != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      info = gtk_text_btree_get_existing_tag_info (tree, tag);
Packit Service fb6fa5
Packit Service fb6fa5
      if (info->tag_root == NULL)
Packit Service fb6fa5
        return NULL;
Packit Service fb6fa5
Packit Service fb6fa5
      node = info->tag_root;
Packit Service fb6fa5
      /* We know the tag root has instances of the given
Packit Service fb6fa5
         tag below it */
Packit Service fb6fa5
Packit Service fb6fa5
      while (node->level > 0)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          g_assert (node != NULL); /* Failure probably means bad tag summaries. */
Packit Service fb6fa5
          last_node = NULL;
Packit Service fb6fa5
          node = node->children.node;
Packit Service fb6fa5
          while (node != NULL)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              if (gtk_text_btree_node_has_tag (node, tag))
Packit Service fb6fa5
                last_node = node;
Packit Service fb6fa5
              node = node->next;
Packit Service fb6fa5
            }
Packit Service fb6fa5
Packit Service fb6fa5
          node = last_node;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (node != NULL); /* The tag summaries said some node had
Packit Service fb6fa5
                                  tag toggles... */
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (node->level == 0);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Find the last line in this node */
Packit Service fb6fa5
      line = node->children.line;
Packit Service fb6fa5
      while (line->next != NULL)
Packit Service fb6fa5
        line = line->next;
Packit Service fb6fa5
Packit Service fb6fa5
      return line;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* This search can't be done efficiently at the moment,
Packit Service fb6fa5
         at least not without complexity.
Packit Service fb6fa5
         So, we just return the last line.
Packit Service fb6fa5
      */
Packit Service fb6fa5
      return _gtk_text_btree_get_end_iter_line (tree);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
/*
Packit Service fb6fa5
 * Lines
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
gint
Packit Service fb6fa5
_gtk_text_line_get_number (GtkTextLine *line)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLine *line2;
Packit Service fb6fa5
  GtkTextBTreeNode *node, *parent, *node2;
Packit Service fb6fa5
  int index;
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * First count how many lines precede this one in its level-0
Packit Service fb6fa5
   * GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  node = line->parent;
Packit Service fb6fa5
  index = 0;
Packit Service fb6fa5
  for (line2 = node->children.line; line2 != line;
Packit Service fb6fa5
       line2 = line2->next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (line2 == NULL)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          g_error ("gtk_text_btree_line_number couldn't find line");
Packit Service fb6fa5
        }
Packit Service fb6fa5
      index += 1;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * Now work up through the levels of the tree one at a time,
Packit Service fb6fa5
   * counting how many lines are in GtkTextBTreeNodes preceding the current
Packit Service fb6fa5
   * GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  for (parent = node->parent ; parent != NULL;
Packit Service fb6fa5
       node = parent, parent = parent->parent)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      for (node2 = parent->children.node; node2 != node;
Packit Service fb6fa5
           node2 = node2->next)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          if (node2 == NULL)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              g_error ("gtk_text_btree_line_number couldn't find GtkTextBTreeNode");
Packit Service fb6fa5
            }
Packit Service fb6fa5
          index += node2->num_lines;
Packit Service fb6fa5
        }
Packit Service fb6fa5
    }
Packit Service fb6fa5
  return index;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static GtkTextLineSegment*
Packit Service fb6fa5
find_toggle_segment_before_char (GtkTextLine *line,
Packit Service fb6fa5
                                 gint char_in_line,
Packit Service fb6fa5
                                 GtkTextTag *tag)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  GtkTextLineSegment *toggle_seg;
Packit Service fb6fa5
  int index;
Packit Service fb6fa5
Packit Service fb6fa5
  toggle_seg = NULL;
Packit Service fb6fa5
  index = 0;
Packit Service fb6fa5
  seg = line->segments;
Packit Service fb6fa5
  while ( (index + seg->char_count) <= char_in_line )
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (((seg->type == &gtk_text_toggle_on_type)
Packit Service fb6fa5
           || (seg->type == &gtk_text_toggle_off_type))
Packit Service fb6fa5
          && (seg->body.toggle.info->tag == tag))
Packit Service fb6fa5
        toggle_seg = seg;
Packit Service fb6fa5
Packit Service fb6fa5
      index += seg->char_count;
Packit Service fb6fa5
      seg = seg->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return toggle_seg;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static GtkTextLineSegment*
Packit Service fb6fa5
find_toggle_segment_before_byte (GtkTextLine *line,
Packit Service fb6fa5
                                 gint byte_in_line,
Packit Service fb6fa5
                                 GtkTextTag *tag)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  GtkTextLineSegment *toggle_seg;
Packit Service fb6fa5
  int index;
Packit Service fb6fa5
Packit Service fb6fa5
  toggle_seg = NULL;
Packit Service fb6fa5
  index = 0;
Packit Service fb6fa5
  seg = line->segments;
Packit Service fb6fa5
  while ( (index + seg->byte_count) <= byte_in_line )
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (((seg->type == &gtk_text_toggle_on_type)
Packit Service fb6fa5
           || (seg->type == &gtk_text_toggle_off_type))
Packit Service fb6fa5
          && (seg->body.toggle.info->tag == tag))
Packit Service fb6fa5
        toggle_seg = seg;
Packit Service fb6fa5
Packit Service fb6fa5
      index += seg->byte_count;
Packit Service fb6fa5
      seg = seg->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return toggle_seg;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
find_toggle_outside_current_line (GtkTextLine *line,
Packit Service fb6fa5
                                  GtkTextBTree *tree,
Packit Service fb6fa5
                                  GtkTextTag *tag)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextBTreeNode *node;
Packit Service fb6fa5
  GtkTextLine *sibling_line;
Packit Service fb6fa5
  GtkTextLineSegment *seg;
Packit Service fb6fa5
  GtkTextLineSegment *toggle_seg;
Packit Service fb6fa5
  int toggles;
Packit Service fb6fa5
  GtkTextTagInfo *info = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * No toggle in this line.  Look for toggles for the tag in lines
Packit Service fb6fa5
   * that are predecessors of line but under the same
Packit Service fb6fa5
   * level-0 GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
  toggle_seg = NULL;
Packit Service fb6fa5
  sibling_line = line->parent->children.line;
Packit Service fb6fa5
  while (sibling_line != line)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      seg = sibling_line->segments;
Packit Service fb6fa5
      while (seg != NULL)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          if (((seg->type == &gtk_text_toggle_on_type)
Packit Service fb6fa5
               || (seg->type == &gtk_text_toggle_off_type))
Packit Service fb6fa5
              && (seg->body.toggle.info->tag == tag))
Packit Service fb6fa5
            toggle_seg = seg;
Packit Service fb6fa5
Packit Service fb6fa5
          seg = seg->next;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      sibling_line = sibling_line->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (toggle_seg != NULL)
Packit Service fb6fa5
    return (toggle_seg->type == &gtk_text_toggle_on_type);
Packit Service fb6fa5
Packit Service fb6fa5
  /*
Packit Service fb6fa5
   * No toggle in this GtkTextBTreeNode.  Scan upwards through the ancestors of
Packit Service fb6fa5
   * this GtkTextBTreeNode, counting the number of toggles of the given tag in
Packit Service fb6fa5
   * siblings that precede that GtkTextBTreeNode.
Packit Service fb6fa5
   */
Packit Service fb6fa5
Packit Service fb6fa5
  info = gtk_text_btree_get_existing_tag_info (tree, tag);
Packit Service fb6fa5
Packit Service fb6fa5
  if (info == NULL)
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  toggles = 0;
Packit Service