Blame gtk/gtktextsegment.c

Packit 98cdb6
/*
Packit 98cdb6
 * gtktextsegment.c --
Packit 98cdb6
 *
Packit 98cdb6
 * Code for segments in general, and toggle/char segments in particular.
Packit 98cdb6
 *
Packit 98cdb6
 * Copyright (c) 1992-1994 The Regents of the University of California.
Packit 98cdb6
 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
Packit 98cdb6
 * Copyright (c) 2000      Red Hat, Inc.
Packit 98cdb6
 * Tk -> Gtk port by Havoc Pennington <hp@redhat.com>
Packit 98cdb6
 *
Packit 98cdb6
 * This software is copyrighted by the Regents of the University of
Packit 98cdb6
 * California, Sun Microsystems, Inc., and other parties.  The
Packit 98cdb6
 * following terms apply to all files associated with the software
Packit 98cdb6
 * unless explicitly disclaimed in individual files.
Packit 98cdb6
 *
Packit 98cdb6
 * The authors hereby grant permission to use, copy, modify,
Packit 98cdb6
 * distribute, and license this software and its documentation for any
Packit 98cdb6
 * purpose, provided that existing copyright notices are retained in
Packit 98cdb6
 * all copies and that this notice is included verbatim in any
Packit 98cdb6
 * distributions. No written agreement, license, or royalty fee is
Packit 98cdb6
 * required for any of the authorized uses.  Modifications to this
Packit 98cdb6
 * software may be copyrighted by their authors and need not follow
Packit 98cdb6
 * the licensing terms described here, provided that the new terms are
Packit 98cdb6
 * clearly indicated on the first page of each file where they apply.
Packit 98cdb6
 *
Packit 98cdb6
 * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
Packit 98cdb6
 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
Packit 98cdb6
 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
Packit 98cdb6
 * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
Packit 98cdb6
 * OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 98cdb6
 *
Packit 98cdb6
 * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
Packit 98cdb6
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
Packit 98cdb6
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
Packit 98cdb6
 * NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
Packit 98cdb6
 * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
Packit 98cdb6
 * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Packit 98cdb6
 *
Packit 98cdb6
 * GOVERNMENT USE: If you are acquiring this software on behalf of the
Packit 98cdb6
 * U.S. government, the Government shall have only "Restricted Rights"
Packit 98cdb6
 * in the software and related documentation as defined in the Federal
Packit 98cdb6
 * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
Packit 98cdb6
 * are acquiring the software on behalf of the Department of Defense,
Packit 98cdb6
 * the software shall be classified as "Commercial Computer Software"
Packit 98cdb6
 * and the Government shall have only "Restricted Rights" as defined
Packit 98cdb6
 * in Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
Packit 98cdb6
 * foregoing, the authors grant the U.S. Government and others acting
Packit 98cdb6
 * in its behalf permission to use and distribute the software in
Packit 98cdb6
 * accordance with the terms specified in this license.
Packit 98cdb6
 *
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
Packit 98cdb6
#include "config.h"
Packit 98cdb6
#include "gtktextbtree.h"
Packit 98cdb6
#include <string.h>
Packit 98cdb6
#include <stdlib.h>
Packit 98cdb6
#include <stdio.h>
Packit 98cdb6
#include "gtktexttag.h"
Packit 98cdb6
#include "gtktexttagtable.h"
Packit 98cdb6
#include "gtktextlayout.h"
Packit 98cdb6
#include "gtktextiterprivate.h"
Packit 98cdb6
#include "gtkdebug.h"
Packit 98cdb6
#include "gtkalias.h"
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 *
Packit 98cdb6
 * split_segment --
Packit 98cdb6
 *
Packit 98cdb6
 *      This procedure is called before adding or deleting
Packit 98cdb6
 *      segments.  It does three things: (a) it finds the segment
Packit 98cdb6
 *      containing iter;  (b) if there are several such
Packit 98cdb6
 *      segments (because some segments have zero length) then
Packit 98cdb6
 *      it picks the first segment that does not have left
Packit 98cdb6
 *      gravity;  (c) if the index refers to the middle of
Packit 98cdb6
 *      a segment then it splits the segment so that the
Packit 98cdb6
 *      index now refers to the beginning of a segment.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *      The return value is a pointer to the segment just
Packit 98cdb6
 *      before the segment corresponding to iter (as
Packit 98cdb6
 *      described above).  If the segment corresponding to
Packit 98cdb6
 *      iter is the first in its line then the return
Packit 98cdb6
 *      value is NULL.
Packit 98cdb6
 *
Packit 98cdb6
 * Side effects:
Packit 98cdb6
 *      The segment referred to by iter is split unless
Packit 98cdb6
 *      iter refers to its first character.
Packit 98cdb6
 *
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
GtkTextLineSegment*
Packit 98cdb6
gtk_text_line_segment_split (const GtkTextIter *iter)
Packit 98cdb6
{
Packit 98cdb6
  GtkTextLineSegment *prev, *seg;
Packit 98cdb6
  GtkTextBTree *tree;
Packit 98cdb6
  GtkTextLine *line;
Packit 98cdb6
  int count;
Packit 98cdb6
Packit 98cdb6
  line = _gtk_text_iter_get_text_line (iter);
Packit 98cdb6
  tree = _gtk_text_iter_get_btree (iter);
Packit 98cdb6
Packit 98cdb6
  count = gtk_text_iter_get_line_index (iter);
Packit 98cdb6
Packit 98cdb6
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit 98cdb6
    _gtk_text_iter_check (iter);
Packit 98cdb6
  
Packit 98cdb6
  prev = NULL;
Packit 98cdb6
  seg = line->segments;
Packit 98cdb6
Packit 98cdb6
  while (seg != NULL)
Packit 98cdb6
    {
Packit 98cdb6
      if (seg->byte_count > count)
Packit 98cdb6
        {
Packit 98cdb6
          if (count == 0)
Packit 98cdb6
            {
Packit 98cdb6
              return prev;
Packit 98cdb6
            }
Packit 98cdb6
          else
Packit 98cdb6
            {
Packit 98cdb6
              g_assert (count != seg->byte_count);
Packit 98cdb6
              g_assert (seg->byte_count > 0);
Packit 98cdb6
Packit 98cdb6
              _gtk_text_btree_segments_changed (tree);
Packit 98cdb6
Packit 98cdb6
              seg = (*seg->type->splitFunc)(seg, count);
Packit 98cdb6
Packit 98cdb6
              if (prev == NULL)
Packit 98cdb6
                line->segments = seg;
Packit 98cdb6
              else
Packit 98cdb6
                prev->next = seg;
Packit 98cdb6
Packit 98cdb6
              return seg;
Packit 98cdb6
            }
Packit 98cdb6
        }
Packit 98cdb6
      else if ((seg->byte_count == 0) && (count == 0)
Packit 98cdb6
               && !seg->type->leftGravity)
Packit 98cdb6
        {
Packit 98cdb6
          return prev;
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
      count -= seg->byte_count;
Packit 98cdb6
      prev = seg;
Packit 98cdb6
      seg = seg->next;
Packit 98cdb6
    }
Packit 98cdb6
  g_error ("split_segment reached end of line!");
Packit 98cdb6
  return NULL;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 * Macros that determine how much space to allocate for new segments:
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
#define CSEG_SIZE(chars) ((unsigned) (G_STRUCT_OFFSET (GtkTextLineSegment, body) \
Packit 98cdb6
        + 1 + (chars)))
Packit 98cdb6
#define TSEG_SIZE ((unsigned) (G_STRUCT_OFFSET (GtkTextLineSegment, body) \
Packit 98cdb6
        + sizeof (GtkTextToggleBody)))
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 * Type functions
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
char_segment_self_check (GtkTextLineSegment *seg)
Packit 98cdb6
{
Packit 98cdb6
  /* This function checks the segment itself, but doesn't
Packit 98cdb6
     assume the segment has been validly inserted into
Packit 98cdb6
     the btree. */
Packit 98cdb6
Packit 98cdb6
  g_assert (seg != NULL);
Packit 98cdb6
Packit 98cdb6
  if (seg->byte_count <= 0)
Packit 98cdb6
    {
Packit 98cdb6
      g_error ("segment has size <= 0");
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (strlen (seg->body.chars) != seg->byte_count)
Packit 98cdb6
    {
Packit 98cdb6
      g_error ("segment has wrong size");
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (g_utf8_strlen (seg->body.chars, seg->byte_count) != seg->char_count)
Packit 98cdb6
    {
Packit 98cdb6
      g_error ("char segment has wrong character count");
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GtkTextLineSegment*
Packit 98cdb6
_gtk_char_segment_new (const gchar *text, guint len)
Packit 98cdb6
{
Packit 98cdb6
  GtkTextLineSegment *seg;
Packit 98cdb6
Packit 98cdb6
  g_assert (gtk_text_byte_begins_utf8_char (text));
Packit 98cdb6
Packit 98cdb6
  seg = g_malloc (CSEG_SIZE (len));
Packit 98cdb6
  seg->type = (GtkTextLineSegmentClass *)&gtk_text_char_type;
Packit 98cdb6
  seg->next = NULL;
Packit 98cdb6
  seg->byte_count = len;
Packit 98cdb6
  memcpy (seg->body.chars, text, len);
Packit 98cdb6
  seg->body.chars[len] = '\0';
Packit 98cdb6
Packit 98cdb6
  seg->char_count = g_utf8_strlen (seg->body.chars, seg->byte_count);
Packit 98cdb6
Packit 98cdb6
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit 98cdb6
    char_segment_self_check (seg);
Packit 98cdb6
Packit 98cdb6
  return seg;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GtkTextLineSegment*
Packit 98cdb6
_gtk_char_segment_new_from_two_strings (const gchar *text1, 
Packit 98cdb6
					guint        len1, 
Packit 98cdb6
					guint        chars1,
Packit 98cdb6
                                        const gchar *text2, 
Packit 98cdb6
					guint        len2, 
Packit 98cdb6
					guint        chars2)
Packit 98cdb6
{
Packit 98cdb6
  GtkTextLineSegment *seg;
Packit 98cdb6
Packit 98cdb6
  g_assert (gtk_text_byte_begins_utf8_char (text1));
Packit 98cdb6
  g_assert (gtk_text_byte_begins_utf8_char (text2));
Packit 98cdb6
Packit 98cdb6
  seg = g_malloc (CSEG_SIZE (len1+len2));
Packit 98cdb6
  seg->type = &gtk_text_char_type;
Packit 98cdb6
  seg->next = NULL;
Packit 98cdb6
  seg->byte_count = len1 + len2;
Packit 98cdb6
  memcpy (seg->body.chars, text1, len1);
Packit 98cdb6
  memcpy (seg->body.chars + len1, text2, len2);
Packit 98cdb6
  seg->body.chars[len1+len2] = '\0';
Packit 98cdb6
Packit 98cdb6
  seg->char_count = chars1 + chars2;
Packit 98cdb6
Packit 98cdb6
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit 98cdb6
    char_segment_self_check (seg);
Packit 98cdb6
Packit 98cdb6
  return seg;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 *
Packit 98cdb6
 * char_segment_split_func --
Packit 98cdb6
 *
Packit 98cdb6
 *      This procedure implements splitting for character segments.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *      The return value is a pointer to a chain of two segments
Packit 98cdb6
 *      that have the same characters as segPtr except split
Packit 98cdb6
 *      among the two segments.
Packit 98cdb6
 *
Packit 98cdb6
 * Side effects:
Packit 98cdb6
 *      Storage for segPtr is freed.
Packit 98cdb6
 *
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
static GtkTextLineSegment *
Packit 98cdb6
char_segment_split_func (GtkTextLineSegment *seg, int index)
Packit 98cdb6
{
Packit 98cdb6
  GtkTextLineSegment *new1, *new2;
Packit 98cdb6
Packit 98cdb6
  g_assert (index < seg->byte_count);
Packit 98cdb6
Packit 98cdb6
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit 98cdb6
    {
Packit 98cdb6
      char_segment_self_check (seg);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  new1 = _gtk_char_segment_new (seg->body.chars, index);
Packit 98cdb6
  new2 = _gtk_char_segment_new (seg->body.chars + index, seg->byte_count - index);
Packit 98cdb6
Packit 98cdb6
  g_assert (gtk_text_byte_begins_utf8_char (new1->body.chars));
Packit 98cdb6
  g_assert (gtk_text_byte_begins_utf8_char (new2->body.chars));
Packit 98cdb6
  g_assert (new1->byte_count + new2->byte_count == seg->byte_count);
Packit 98cdb6
  g_assert (new1->char_count + new2->char_count == seg->char_count);
Packit 98cdb6
Packit 98cdb6
  new1->next = new2;
Packit 98cdb6
  new2->next = seg->next;
Packit 98cdb6
Packit 98cdb6
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit 98cdb6
    {
Packit 98cdb6
      char_segment_self_check (new1);
Packit 98cdb6
      char_segment_self_check (new2);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  g_free (seg);
Packit 98cdb6
  return new1;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 *
Packit 98cdb6
 * char_segment_cleanup_func --
Packit 98cdb6
 *
Packit 98cdb6
 *      This procedure merges adjacent character segments into
Packit 98cdb6
 *      a single character segment, if possible.
Packit 98cdb6
 *
Packit 98cdb6
 * Arguments:
Packit 98cdb6
 *      segPtr: Pointer to the first of two adjacent segments to
Packit 98cdb6
 *              join.
Packit 98cdb6
 *      line:   Line containing segments (not used).
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *      The return value is a pointer to the first segment in
Packit 98cdb6
 *      the (new) list of segments that used to start with segPtr.
Packit 98cdb6
 *
Packit 98cdb6
 * Side effects:
Packit 98cdb6
 *      Storage for the segments may be allocated and freed.
Packit 98cdb6
 *
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
        /* ARGSUSED */
Packit 98cdb6
static GtkTextLineSegment *
Packit 98cdb6
char_segment_cleanup_func (GtkTextLineSegment *segPtr, GtkTextLine *line)
Packit 98cdb6
{
Packit 98cdb6
  GtkTextLineSegment *segPtr2, *newPtr;
Packit 98cdb6
Packit 98cdb6
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit 98cdb6
    char_segment_self_check (segPtr);
Packit 98cdb6
Packit 98cdb6
  segPtr2 = segPtr->next;
Packit 98cdb6
  if ((segPtr2 == NULL) || (segPtr2->type != &gtk_text_char_type))
Packit 98cdb6
    {
Packit 98cdb6
      return segPtr;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  newPtr =
Packit 98cdb6
    _gtk_char_segment_new_from_two_strings (segPtr->body.chars, 
Packit 98cdb6
					    segPtr->byte_count,
Packit 98cdb6
					    segPtr->char_count,
Packit 98cdb6
                                            segPtr2->body.chars, 
Packit 98cdb6
					    segPtr2->byte_count,
Packit 98cdb6
					    segPtr2->char_count);
Packit 98cdb6
Packit 98cdb6
  newPtr->next = segPtr2->next;
Packit 98cdb6
Packit 98cdb6
  if (gtk_debug_flags & GTK_DEBUG_TEXT)
Packit 98cdb6
    char_segment_self_check (newPtr);
Packit 98cdb6
Packit 98cdb6
  g_free (segPtr);
Packit 98cdb6
  g_free (segPtr2);
Packit 98cdb6
  return newPtr;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 *
Packit 98cdb6
 * char_segment_delete_func --
Packit 98cdb6
 *
Packit 98cdb6
 *      This procedure is invoked to delete a character segment.
Packit 98cdb6
 *
Packit 98cdb6
 * Arguments:
Packit 98cdb6
 *      segPtr   : Segment to delete
Packit 98cdb6
 *      line     : Line containing segment
Packit 98cdb6
 *      treeGone : Non-zero means the entire tree is being
Packit 98cdb6
 *                 deleted, so everything must get cleaned up.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *      Always returns 0 to indicate that the segment was deleted.
Packit 98cdb6
 *
Packit 98cdb6
 * Side effects:
Packit 98cdb6
 *      Storage for the segment is freed.
Packit 98cdb6
 *
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
        /* ARGSUSED */
Packit 98cdb6
static int
Packit 98cdb6
char_segment_delete_func (GtkTextLineSegment *segPtr, GtkTextLine *line, int treeGone)
Packit 98cdb6
{
Packit 98cdb6
  g_free ((char*) segPtr);
Packit 98cdb6
  return 0;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 *
Packit 98cdb6
 * char_segment_check_func --
Packit 98cdb6
 *
Packit 98cdb6
 *      This procedure is invoked to perform consistency checks
Packit 98cdb6
 *      on character segments.
Packit 98cdb6
 *
Packit 98cdb6
 * Arguments:
Packit 98cdb6
 *      segPtr : Segment to check
Packit 98cdb6
 *      line   : Line containing segment
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *      None.
Packit 98cdb6
 *
Packit 98cdb6
 * Side effects:
Packit 98cdb6
 *      If the segment isn't inconsistent then the procedure
Packit 98cdb6
 *      g_errors.
Packit 98cdb6
 *
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
        /* ARGSUSED */
Packit 98cdb6
static void
Packit 98cdb6
char_segment_check_func (GtkTextLineSegment *segPtr, GtkTextLine *line)
Packit 98cdb6
{
Packit 98cdb6
  char_segment_self_check (segPtr);
Packit 98cdb6
Packit 98cdb6
  if (segPtr->next != NULL)
Packit 98cdb6
    {
Packit 98cdb6
      if (segPtr->next->type == &gtk_text_char_type)
Packit 98cdb6
        {
Packit 98cdb6
          g_error ("adjacent character segments weren't merged");
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GtkTextLineSegment*
Packit 98cdb6
_gtk_toggle_segment_new (GtkTextTagInfo *info, gboolean on)
Packit 98cdb6
{
Packit 98cdb6
  GtkTextLineSegment *seg;
Packit 98cdb6
Packit 98cdb6
  seg = g_malloc (TSEG_SIZE);
Packit 98cdb6
Packit 98cdb6
  seg->type = on ? &gtk_text_toggle_on_type : &gtk_text_toggle_off_type;
Packit 98cdb6
Packit 98cdb6
  seg->next = NULL;
Packit 98cdb6
Packit 98cdb6
  seg->byte_count = 0;
Packit 98cdb6
  seg->char_count = 0;
Packit 98cdb6
Packit 98cdb6
  seg->body.toggle.info = info;
Packit 98cdb6
  seg->body.toggle.inNodeCounts = 0;
Packit 98cdb6
Packit 98cdb6
  return seg;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 *
Packit 98cdb6
 * toggle_segment_delete_func --
Packit 98cdb6
 *
Packit 98cdb6
 *      This procedure is invoked to delete toggle segments.
Packit 98cdb6
 *
Packit 98cdb6
 * Arguments:
Packit 98cdb6
 *      segPtr   : Segment to check
Packit 98cdb6
 *      line     : Line containing segment
Packit 98cdb6
 *      treeGone : Non-zero means the entire tree is being
Packit 98cdb6
 *                 deleted so everything must get cleaned up
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *      Returns 1 to indicate that the segment may not be deleted,
Packit 98cdb6
 *      unless the entire B-tree is going away.
Packit 98cdb6
 *
Packit 98cdb6
 * Side effects:
Packit 98cdb6
 *      If the tree is going away then the toggle's memory is
Packit 98cdb6
 *      freed;  otherwise the toggle counts in GtkTextBTreeNodes above the
Packit 98cdb6
 *      segment get updated.
Packit 98cdb6
 *
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
static int
Packit 98cdb6
toggle_segment_delete_func (GtkTextLineSegment *segPtr, GtkTextLine *line, int treeGone)
Packit 98cdb6
{
Packit 98cdb6
  if (treeGone)
Packit 98cdb6
    {
Packit 98cdb6
      g_free ((char *) segPtr);
Packit 98cdb6
      return 0;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  /*
Packit 98cdb6
   * This toggle is in the middle of a range of characters that's
Packit 98cdb6
   * being deleted.  Refuse to die.  We'll be moved to the end of
Packit 98cdb6
   * the deleted range and our cleanup procedure will be called
Packit 98cdb6
   * later.  Decrement GtkTextBTreeNode toggle counts here, and set a flag
Packit 98cdb6
   * so we'll re-increment them in the cleanup procedure.
Packit 98cdb6
   */
Packit 98cdb6
Packit 98cdb6
  if (segPtr->body.toggle.inNodeCounts)
Packit 98cdb6
    {
Packit 98cdb6
      _gtk_change_node_toggle_count (line->parent,
Packit 98cdb6
                                     segPtr->body.toggle.info, -1);
Packit 98cdb6
      segPtr->body.toggle.inNodeCounts = 0;
Packit 98cdb6
    }
Packit 98cdb6
  return 1;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 *
Packit 98cdb6
 * toggle_segment_cleanup_func --
Packit 98cdb6
 *
Packit 98cdb6
 *      This procedure is called when a toggle is part of a line that's
Packit 98cdb6
 *      been modified in some way.  It's invoked after the
Packit 98cdb6
 *      modifications are complete.
Packit 98cdb6
 *
Packit 98cdb6
 * Arguments:
Packit 98cdb6
 *      segPtr : Segment to check
Packit 98cdb6
 *      line   : Line that now contains segment
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *      The return value is the head segment in a new list
Packit 98cdb6
 *      that is to replace the tail of the line that used to
Packit 98cdb6
 *      start at segPtr.  This allows the procedure to delete
Packit 98cdb6
 *      or modify segPtr.
Packit 98cdb6
 *
Packit 98cdb6
 * Side effects:
Packit 98cdb6
 *      Toggle counts in the GtkTextBTreeNodes above the new line will be
Packit 98cdb6
 *      updated if they're not already.  Toggles may be collapsed
Packit 98cdb6
 *      if there are duplicate toggles at the same position.
Packit 98cdb6
 *
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
static GtkTextLineSegment *
Packit 98cdb6
toggle_segment_cleanup_func (GtkTextLineSegment *segPtr, GtkTextLine *line)
Packit 98cdb6
{
Packit 98cdb6
  GtkTextLineSegment *segPtr2, *prevPtr;
Packit 98cdb6
  int counts;
Packit 98cdb6
Packit 98cdb6
  /*
Packit 98cdb6
   * If this is a toggle-off segment, look ahead through the next
Packit 98cdb6
   * segments to see if there's a toggle-on segment for the same tag
Packit 98cdb6
   * before any segments with non-zero size.  If so then the two
Packit 98cdb6
   * toggles cancel each other;  remove them both.
Packit 98cdb6
   */
Packit 98cdb6
Packit 98cdb6
  if (segPtr->type == &gtk_text_toggle_off_type)
Packit 98cdb6
    {
Packit 98cdb6
      for (prevPtr = segPtr, segPtr2 = prevPtr->next;
Packit 98cdb6
           (segPtr2 != NULL) && (segPtr2->byte_count == 0);
Packit 98cdb6
           prevPtr = segPtr2, segPtr2 = prevPtr->next)
Packit 98cdb6
        {
Packit 98cdb6
          if (segPtr2->type != &gtk_text_toggle_on_type)
Packit 98cdb6
            {
Packit 98cdb6
              continue;
Packit 98cdb6
            }
Packit 98cdb6
          if (segPtr2->body.toggle.info != segPtr->body.toggle.info)
Packit 98cdb6
            {
Packit 98cdb6
              continue;
Packit 98cdb6
            }
Packit 98cdb6
          counts = segPtr->body.toggle.inNodeCounts
Packit 98cdb6
            + segPtr2->body.toggle.inNodeCounts;
Packit 98cdb6
          if (counts != 0)
Packit 98cdb6
            {
Packit 98cdb6
              _gtk_change_node_toggle_count (line->parent,
Packit 98cdb6
                                             segPtr->body.toggle.info, -counts);
Packit 98cdb6
            }
Packit 98cdb6
          prevPtr->next = segPtr2->next;
Packit 98cdb6
          g_free ((char *) segPtr2);
Packit 98cdb6
          segPtr2 = segPtr->next;
Packit 98cdb6
          g_free ((char *) segPtr);
Packit 98cdb6
          return segPtr2;
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (!segPtr->body.toggle.inNodeCounts)
Packit 98cdb6
    {
Packit 98cdb6
      _gtk_change_node_toggle_count (line->parent,
Packit 98cdb6
                                     segPtr->body.toggle.info, 1);
Packit 98cdb6
      segPtr->body.toggle.inNodeCounts = 1;
Packit 98cdb6
    }
Packit 98cdb6
  return segPtr;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 *
Packit 98cdb6
 * toggle_segment_line_change_func --
Packit 98cdb6
 *
Packit 98cdb6
 *      This procedure is invoked when a toggle segment is about
Packit 98cdb6
 *      to move from one line to another.
Packit 98cdb6
 *
Packit 98cdb6
 * Arguments:
Packit 98cdb6
 *      segPtr : Segment to check
Packit 98cdb6
 *      line   : Line that used to contain segment
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *      None.
Packit 98cdb6
 *
Packit 98cdb6
 * Side effects:
Packit 98cdb6
 *      Toggle counts are decremented in the GtkTextBTreeNodes above the line.
Packit 98cdb6
 *
Packit 98cdb6
 *--------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
toggle_segment_line_change_func (GtkTextLineSegment *segPtr, GtkTextLine *line)
Packit 98cdb6
{
Packit 98cdb6
  if (segPtr->body.toggle.inNodeCounts)
Packit 98cdb6
    {
Packit 98cdb6
      _gtk_change_node_toggle_count (line->parent,
Packit 98cdb6
                                     segPtr->body.toggle.info, -1);
Packit 98cdb6
      segPtr->body.toggle.inNodeCounts = 0;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 * Virtual tables
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
const GtkTextLineSegmentClass gtk_text_char_type = {
Packit 98cdb6
  "character",                          /* name */
Packit 98cdb6
  0,                                            /* leftGravity */
Packit 98cdb6
  char_segment_split_func,                              /* splitFunc */
Packit 98cdb6
  char_segment_delete_func,                             /* deleteFunc */
Packit 98cdb6
  char_segment_cleanup_func,                            /* cleanupFunc */
Packit 98cdb6
  NULL,         /* lineChangeFunc */
Packit 98cdb6
  char_segment_check_func                               /* checkFunc */
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 * Type record for segments marking the beginning of a tagged
Packit 98cdb6
 * range:
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
const GtkTextLineSegmentClass gtk_text_toggle_on_type = {
Packit 98cdb6
  "toggleOn",                                   /* name */
Packit 98cdb6
  0,                                            /* leftGravity */
Packit 98cdb6
  NULL,                 /* splitFunc */
Packit 98cdb6
  toggle_segment_delete_func,                           /* deleteFunc */
Packit 98cdb6
  toggle_segment_cleanup_func,                          /* cleanupFunc */
Packit 98cdb6
  toggle_segment_line_change_func,                      /* lineChangeFunc */
Packit 98cdb6
  _gtk_toggle_segment_check_func                        /* checkFunc */
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 * Type record for segments marking the end of a tagged
Packit 98cdb6
 * range:
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
const GtkTextLineSegmentClass gtk_text_toggle_off_type = {
Packit 98cdb6
  "toggleOff",                          /* name */
Packit 98cdb6
  1,                                            /* leftGravity */
Packit 98cdb6
  NULL,                 /* splitFunc */
Packit 98cdb6
  toggle_segment_delete_func,                           /* deleteFunc */
Packit 98cdb6
  toggle_segment_cleanup_func,                          /* cleanupFunc */
Packit 98cdb6
  toggle_segment_line_change_func,                      /* lineChangeFunc */
Packit 98cdb6
  _gtk_toggle_segment_check_func                        /* checkFunc */
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
#define __GTK_TEXT_SEGMENT_C__
Packit 98cdb6
#include "gtkaliasdef.c"