/* ########################################################################

			      selection.c

   File: selection.c
   Path: /users/lf/c/X11/xcoral-2.5/selection.c
   Description: 
   Created: Sat Sep 14 11:46:16 MET 1996
   Author: Lionel Fournigault
   Modified: Sat Sep 14 11:46:18 MET 1996
   Last maintained by: Lionel Fournigault

   RCS $Revision$ $State$
   

   ########################################################################

   Note: 

   ########################################################################

   Copyright (c) : Lionel Fournigault

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

   ######################################################################## */

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>

#include "main_text.h"
#include "parse.h"
#include "text_cursor.h"
#include "page.h"
#include "chars_cmds.h"

FCT (static void, cur_line_sup_old, (Text *text));
FCT (static void, cur_line_inf_old, (Text *text));
FCT (static void, cur_line_equal_old, (Text *text));
FCT (static void, video_after_cursor, (Text *text));
FCT (static void, video_before_cursor, (Text *text));
FCT (static void, get_bytes_selection, (Text *text));
FCT (static void, handle_select_internal, (Text *text));
FCT (static void, display_first_and_last, (Text *text));
FCT (static void, display_one_line, (Text *text));

FCT (void, ClearSelection, (Text *text, int select) );
FCT (void, RefreshSelection, (Text *text) );
FCT (void, HandleSelection, (Text *text, XEvent *ev) );
FCT (void, StartSelection, (Text *text) );
FCT (void, EndSelection, (Text *text) );
FCT (void, UpdateSelection, (Text *text) );
FCT (void, ClearSelectionIfNeeded, (Text *text) );

extern Display *dpy;
static XRectangle rect [8];
static int nrect;
static int root_x, root_y, win_x, win_y;
static int select_run = False;
static XEvent event;
static scroll_x = 0;
static GC sgc;

/*
**	Function name : InitSelection
**
**	Description :
**	Input :
**	Output :
*/
void InitSelection(dpy, fg, bg)
    Display *dpy;
    unsigned long fg, bg;
{
    XGCValues gcv;
    GC gc;
    unsigned long gcm, sfg;
    int result;
    char *s_color;

    if (UseColor() == False) {
      gcm = 0;
      gcm |= GCFunction;	gcv.function = GXxor;
      gcm |= GCPlaneMask;	gcv.plane_mask = fg ^ bg;
      gcm |= GCForeground;	gcv.foreground = fg ^ bg;
      gcm |= GCBackground;	gcv.background = bg;
      sgc = XCreateGC (dpy, DefaultRootWindow (dpy), gcm, &gcv );
      return;
    }

    /* color display */
    s_color = (char *) getenv("XCORAL_SELECTION");
    if (s_color == NULL) {
      sfg = PixelValue (dpy, "gray", &result);
      if (result != False)
	fg = sfg;
    }
    else {
      sfg = PixelValue (dpy, s_color, &result);
      if (result != False)
	fg = sfg;
    }
    if (result == False)
      fg = BlackPixel(dpy, DefaultScreen(dpy));

    gc = DefaultGC (dpy, DefaultScreen(dpy));
    gcm = 0;
    gcm |= GCFunction;	gcv.function =  GXxor;
    gcm |= GCPlaneMask;	gcv.plane_mask = fg ^ bg;
    gcm |= GCForeground;gcv.foreground = fg ^ bg;

    sgc = XCreateGC (dpy, DefaultRootWindow (dpy), gcm, &gcv );
}

/*
**	Function name : HandleSelection
**
**	Description :
**	Input :
**	Output :
*/
void HandleSelection(text, ev)
    Text *text;
    XEvent *ev;
{
  Window root, child;
  unsigned int keys_buttons;
  int i, mh;

  (void) ClearSelection(text, True);
  
  text -> selection -> x_sl = text -> x_pos;
  text -> selection -> x_el = text -> x_pos;
  text -> selection -> start_line = text-> no_current_line;
  text -> selection -> end_line = text-> no_current_line;
  text -> selection -> ncfl_sl = GetNcFromLeft (text -> buf);
  text -> selection -> ncfl_el = 0;
  text -> selection -> s_sl = text -> sl;
  
  for (i=0;i<8;i++) {
    rect[i].height = text -> font_height;
    rect[i].x = rect[i].y = rect[i].width = 0;
  }
  
  mh = text -> y_or + (text -> lines_in_page * text -> font_height);
  
  for ( ;; ) {
    XNextEvent ( dpy, &event );
    switch ( event.type ) {
    case ButtonRelease:
      if ((text -> selection -> start_line == text-> no_current_line)
	  && (text -> selection -> x_sl == text -> selection -> x_el)) {
	text -> selection -> select = False;
      }
      else {
	text -> selection -> select = True;
	text -> selection -> ncfl_el = GetNcFromLeft (text -> buf);
	text -> selection -> e_sl = text -> sl;
	(void) get_bytes_selection (text);
      }
      TextCursorOn (text);
      select_run = False;
      return;
    case MotionNotify:
      text -> selection -> select = True;
      select_run = True;
      while ( XCheckMaskEvent ( dpy, ButtonMotionMask, &event ));
      XQueryPointer ( dpy, event.xmotion.window, &root, &child, &root_x,
		     &root_y, &win_x, &win_y, &keys_buttons );

      if (win_y < 0 || win_y > text->height)
	continue;
	
      else if (win_y < text -> y_or) {
	if(text->sl)
	  continue;
	while (XCheckMaskEvent ( dpy,  ButtonReleaseMask | ButtonMotionMask, 
				&event ) == False){
	  if ( (text -> no_current_line - text -> n1) != 1 ) {
	    ScrollNLine ( -1, text );
	    (void) MoveScrollBar ( dpy, text -> swin, CURRENT,
				  text -> no_current_line - text -> n1 - 1 );
	    (void) handle_select_internal (text);
	  }
	  else {
	    (void) MoveScrollBar ( dpy, text -> swin, FIRST, 0 );
	    continue;
	  }
	}
	if ((event.type == ButtonRelease) || (event.type == MotionNotify))
	  XPutBackEvent (dpy, &event);
	TextCursorOn (text);
      }
      else if (win_y > mh ){
	if(text->sl)
	  continue;
	while (XCheckMaskEvent ( dpy,  ButtonReleaseMask | ButtonMotionMask, 
				&event ) == False){
	  if ( text -> no_current_line != text -> lines_in_buf ){
	    ScrollNLine ( 1, text ); 
	    (void) MoveScrollBar ( dpy, text -> swin, CURRENT,
				  text -> no_current_line - text -> n1 - 1 );
	    (void) handle_select_internal (text);
	  }
	  else
	    continue;
	}
	if ((event.type == ButtonRelease) || (event.type == MotionNotify))
	  XPutBackEvent (dpy, &event);
	TextCursorOn (text);
      }
      else
	(void) handle_select_internal (text);
    }
  }
}

/*
**	Function name : handle_select_internal
**
**	Description :
**	Input :
**	Output :
*/
static void handle_select_internal(text)
    Text *text;
{
/* #define DEBUG4 */
  
  int i, sl;
  XRectangle r [1];

  TextCursorOff (text);
  StorePosition (text);

  if (MoveToXYinTextWindow ( text, win_x, win_y ) == -1) {
    HoleToRight ( text -> buf );
    GotoLineNumber ( text, text -> lines_in_buf );
    SetPosition ( text );
    UpdatePage ( text );
  }

  nrect = 0;

  nrect = 0;
  sl = text -> sl;
  TextCursorOn (text); /* Pour savoir si ya eu un scroll horizontal */

  if (sl != text -> sl) {
    /* scroll horizontal. */
    XWarpPointer (dpy, None, text -> window, 0,0,0,0, 
		  text -> x_pos + 4, text -> y_pos + 4);
    text -> selection -> x_el = text -> x_pos;
    (void) RefreshSelection(text);
    while ( XCheckMaskEvent ( dpy, ButtonMotionMask, &event ));
    TextCursorOff (text);
    FreezeTextCursor (text);

    /* Si la video est apres le cursor, il faut ajouter la largeur
       de celui-ci a la position courante de la selection x_el */
    if (text -> selection -> start_line > text -> selection -> end_line)
      text -> selection -> x_el += text -> cursor_width;
    if ((text -> selection -> start_line == text -> selection -> end_line)
	&&(text -> selection -> ncfl_sl > text -> selection -> ncfl_el))
      text -> selection -> x_el += text -> cursor_width;
    return;
  }

  TextCursorOff (text);
  FreezeTextCursor (text);
    
  if (text -> no_current_line > text -> selection -> end_line)
    (void) cur_line_sup_old (text);
  else if (text -> no_current_line < text -> selection -> end_line)
    (void) cur_line_inf_old (text);
  else
    (void) cur_line_equal_old (text);
  
  if (nrect) {
#ifdef DEBUG4
    (void) fprintf (stderr,"=========nrect = %d\n", nrect);
    for (i=0;i<nrect;i++) {
      (void) fprintf (stderr, "\tx = %d y = %d width = %d height = %d\n",
		      rect[i].x, rect[i].y, rect[i].width, rect[i].height );
    }
#endif /* DEBUG4 */
    r[0].x = text -> x_or;
    r[0].width = text -> width - ( 2 * text -> x_or );
    
    r[0].y = text -> y_or;
    r[0].height = text -> lines_in_page * text -> font_height;
    
    XSetClipRectangles ( dpy, sgc, 0, 0, r, 1, False );
    XFillRectangles (dpy, text -> window, sgc, rect, nrect);
    XSetClipMask ( dpy, sgc, None );
    for (i=0;i<8;i++) {
      rect[i].x = rect[i].y = rect[i].width;
      rect[i].height = text -> font_height;
    }
  }
}

/*
**	Function name : video_before_cursor
**
**	Description :
**	Input :
**	Output :
*/
static void video_before_cursor(text)
    Text *text;
{
/* #define DEBUG8 */
  
  if (text -> x_pos > text -> selection -> x_el) {
    /* vers la droite */
#ifdef DEBUG8
    (void) fprintf (stderr, "81\n");
#endif /* DEBUG8 */
    rect[nrect].x = text -> selection -> x_el;
    rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
    rect[nrect].width = text -> x_pos - text -> selection -> x_el;
    nrect ++;
    text -> selection -> x_el = text -> x_pos;
  }
  else {
    /* vers la gauche */
    if (text -> x_pos != text -> selection -> x_el) {
#ifdef DEBUG8
      (void) fprintf (stderr, "82 x_pos = %d x_el = %d\n",
		      text -> x_pos, text -> selection -> x_el);
#endif /* DEBUG8 */
      rect[nrect].x = text -> x_pos;
      rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
      rect[nrect].width = text -> selection -> x_el - text -> x_pos;
      nrect ++;
      text -> selection -> x_el = text -> x_pos;
    }
  }
}

/*
**	Function name : video_after_cursor
**
**	Description :
**	Input :
**	Output :
*/
static void video_after_cursor(text)
    Text *text;
{
/* #define DEBUG9 */
/*  if (text -> x_pos > text -> selection -> x_el) { */
  if (text -> x_pos >= text -> selection -> x_el) {
    /* vers la droite */
#ifdef DEBUG9
    (void) fprintf (stderr, "91\n");
#endif /* DEBUG9 */
    rect[nrect].x = text -> selection -> x_el;
    rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
    rect[nrect].width = text -> x_pos - text -> selection -> x_el;
    nrect ++;
    rect[nrect].x = text -> x_pos;
    rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
    rect[nrect].width = text -> cursor_width;
    nrect ++;
    text -> selection -> x_el = text -> x_pos + text -> cursor_width;
  }
  else {
    /* vers la gauche */
/*    
    if ((text -> x_pos + text -> cursor_width) != text -> selection -> x_sl 
	&& (text -> x_pos + text -> cursor_width) != text -> selection -> x_el){
*/
    if (text -> x_pos < text -> selection -> x_el) {
#ifdef DEBUG9
      (void) fprintf (stderr, "92\n");
#endif /* DEBUG9 */
      rect[nrect].x = text -> x_pos;
      rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
      rect[nrect].width = text -> selection -> x_el - text -> x_pos;
      nrect ++;
      rect[nrect].x = text -> x_pos;
      rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
      rect[nrect].width = text -> cursor_width;
      nrect ++;
      text -> selection -> x_el = text -> x_pos + text -> cursor_width;
    }
  }
}

/*
**	Function name : cur_line_equal_old
**
**	Description :
**	Input :
**	Output :
*/
static void cur_line_equal_old(text)
    Text *text;
{ 
/* #define DEBUG3 */
  
  if (text -> no_current_line < text -> selection -> start_line) {
    /* l'inverse video est a droite du curseur */
    (void) video_after_cursor (text);
  }
  else if (text -> no_current_line > text -> selection -> start_line) {
    /* l'inverse video est a gauche du curseur */
    (void) video_before_cursor (text);
  }
  else {
    /* le caractere initial de la selection est sur la ligne courante */
    if (text -> x_pos >= text -> selection  -> x_sl) {
      /* On se deplace a droite du point initial */
      if (text -> x_pos > text -> selection -> x_el) {
	/* vers la droite */
	if (text -> x_pos != text -> selection -> x_sl) {
#ifdef DEBUG3
	  (void) fprintf (stderr, "35\n");
#endif /* DEBUG3 */
	  rect[nrect].x = text -> selection -> x_el;
	  rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
	  rect[nrect].width = text -> x_pos - text -> selection -> x_el;
	  nrect ++;
	  text -> selection -> x_el = text -> x_pos;
	}
      }
      else {
	/* vers la gauche */
	if (text -> x_pos != text -> selection -> x_el) {
#ifdef DEBUG3
	  (void) fprintf (stderr, "36\n");
#endif /* DEBUG3 */
	  rect[nrect].x = text -> x_pos;
	  rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
	  rect[nrect].width = text -> selection -> x_el - text -> x_pos;
	  nrect ++;
	  text -> selection -> x_el = text -> x_pos;
	}
      }
    }
    else {
      /* On se deplace a gauche du point initial */
      if ( ! (text -> x_pos < text -> selection -> x_el)) {
	/* vers la droite */
#ifdef DEBUG3
	(void) fprintf (stderr, "37\n");
#endif /* DEBUG3 */
	rect[nrect].x = text -> selection -> x_el;
	rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
	rect[nrect].width = text -> x_pos - text -> selection -> x_el;
	nrect ++;
	rect[nrect].x = text -> x_pos;
	rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
	rect[nrect].width = text -> cursor_width;
	nrect ++;
	text -> selection -> x_el = text -> x_pos + text -> cursor_width;
      }
      else {
	/* vers la gauche */
	if ((text -> x_pos + text -> cursor_width) != text -> selection -> x_sl 
	    && (text -> x_pos + text -> cursor_width) != text -> selection -> x_el){
#ifdef DEBUG3
	  (void) fprintf (stderr, "38\n");
#endif /* DEBUG3 */
	  rect[nrect].x = text -> x_pos;
	  rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
	  rect[nrect].width = text -> selection -> x_el - text -> x_pos;
	  nrect ++;
	  rect[nrect].x = text -> x_pos;
	  rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
	  rect[nrect].width = text -> cursor_width;
	  nrect ++;
	  text -> selection -> x_el = text -> x_pos + text -> cursor_width;
	}
      }
    }
  }
}


/*
**	Function name : cur_line_inf_old
**
**	Description :
**	Input :
**	Output :
*/
static void cur_line_inf_old(text)
    Text *text;
{
  /* Nombre de lignes a prendre en compte si on a pas tous les evennements souris */
  int i = text -> selection -> end_line - text -> no_current_line - 1;

/* #define DEBUG2 */
  
  if (i > 0) {
    /* Saut de ligne (on a pas tous les events) */
#ifdef DEBUG2
  (void) fprintf (stderr, "21 i = %d\n", i);
#endif /* DEBUG2 */
    rect[nrect].x = text -> x_or;
    rect[nrect].y = text -> y_or +  ((text -> n1 + 1) *  text -> font_height);
    rect[nrect].width = text -> width - (2 * text -> x_or);
    rect[nrect].height = i * text -> font_height;
    nrect ++;
  }
  
  /* du curseur jusqu'au bord droit */
  rect[nrect].x = text -> x_pos + text -> cursor_width;
  rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
  rect[nrect].width = text -> width - text -> x_or - text -> x_pos 
    - text -> cursor_width;
  nrect ++;

  /* du bord gauche jusqu'au curseur */
  rect[nrect].x = text -> x_or;
  rect[nrect].y = text -> y_or + ((text -> n1 + i + 1) *  text -> font_height);
  rect[nrect].width = text -> selection -> x_el - text -> x_or;
  nrect ++;

  text -> selection -> end_line = text -> no_current_line;
  text -> selection -> x_el = text -> x_pos + text -> cursor_width;
}

/*
**	Function name : cur_line_sup_old
**
**	Description :
**	Input :
**	Output :
*/
static void cur_line_sup_old(text)
    Text *text;
{
  /* Nombre de lignes a prendre en compte si on a pas tous les evennements souris */
  int i = text -> no_current_line - text -> selection -> end_line - 1;

/* #define DEBUG1 */
  
  if (i > 0) {
    /* Saut de plusieurs ligne (on a pas tous les events)*/
#ifdef DEBUG1
  (void) fprintf (stderr, "11 i = %d\n", i);
#endif /* DEBUG1 */
    rect[nrect].x = text -> x_or;
    rect[nrect].y = text -> y_or + ((text -> n1 - i)*  text -> font_height);
    rect[nrect].width = text -> width - (2 * text -> x_or);
    rect[nrect].height = i * text -> font_height;
    nrect ++;
  }

  /* de la position precedente au bord droit */
  rect[nrect].x = text -> selection -> x_el;
  rect[nrect].y = text -> y_or + ((text -> n1 -i -1) *  text -> font_height);
  rect[nrect].width = text -> width - text -> selection -> x_el - text -> x_or;
  nrect ++;

  /* du bord gauche jusqu'au curseur */
  rect[nrect].x = text -> x_or;
  rect[nrect].y = text -> y_or + ((text -> n1) *  text -> font_height);
  rect[nrect].width = text -> x_pos - text -> x_or;
  nrect ++;

  text -> selection -> end_line = text -> no_current_line;
  text -> selection -> x_el = text -> x_pos;
}

/*
**	Function name : ClearSelection
**
**	Description : 
**	Input :
**	Output :
*/
void ClearSelection(text, remove_bytes)
    Text *text;
    int remove_bytes; /* If false, just clear area (expose events),
			 else remove bytes of selection */
{
  int tc_stat = text -> cursor_stat;
  
/*#define DEBUG10*/
  XRectangle rect [1];
  int nl = 0; /* nombre de lignes - 1 dans la selection */
  int nc = 0; /* nombre de lignes entre la ligne courante et la selection */
  int nd = 0;
  int ny = 0;
  
  if (text -> selection -> select == False)
    return;
/*
  if (((text -> selection -> start_line > (text -> no_current_line + text -> n2))
      && (text -> selection -> end_line > (text -> no_current_line + text -> n2)))
      || ((text -> selection -> start_line < (text -> no_current_line - text -> n1))
      && (text -> selection -> end_line < (text -> no_current_line - text -> n1)))) {
*/
  if (SelectionIsVisible(text) != True) {
#ifdef DEBUG10
  (void) fprintf (stderr, "10\n");
#endif /* DEBUG10 */
  }
  else {
    /* La selection est visible */
#ifdef DEBUG10
    (void) fprintf (stderr, "11\n");
#endif /* DEBUG10 */
    /* Calcul du clip */
    nl = text -> selection -> end_line - text -> selection -> start_line;
    nc = text -> no_current_line - text -> selection -> end_line;
    rect [0].x = text -> x_or;
    rect [0].y = text -> y_or;
    rect [0].width = text -> width - ( 2 * text -> x_or );
    rect [0].height = (nl<0) ? ((-nl+1) * text -> font_height)
			     : ((nl+1) * text -> font_height);

    if(nl>0) {
      /* Selection vers la fin du buffer */
#ifdef DEBUG10
    (void) fprintf (stderr, "12\n");
#endif /* DEBUG10 */
      nd = text -> no_current_line - text -> selection -> start_line;
      rect [0].y += ((text -> n1 - nd) * text -> font_height);
      if (rect [0].y < text -> y_or)
	rect [0].y = text -> y_or;
      if ((rect [0].y + rect [0].height)>
	  (text->y_or+(text->lines_in_page*text->font_height)))
	rect [0].height = (text->lines_in_page*text->font_height)
	  -rect [0].y + text -> y_or;
    }
    else if (nl<0) {
      /* Selection vers le debut du buffer */
#ifdef DEBUG10
    (void) fprintf (stderr, "13\n");
#endif /* DEBUG10 */
      nd = text -> no_current_line - text -> selection -> end_line;
      rect [0].y += ((text -> n1 - nd) * text -> font_height);
      if (rect [0].y < text -> y_or)
	rect [0].y = text -> y_or;
      if ((rect [0].y + rect [0].height)>
	  (text->y_or+(text->lines_in_page*text->font_height)))
	rect [0].height = (text->lines_in_page*text->font_height)
	  -rect [0].y + text->y_or;
    }
    else {
      /* une seule ligne */
      rect [0].y += ((text -> n1 - nc)* text -> font_height);
    }

    /* On verifie qu'on ne sort pas de la page */
    if ((ny=(text->y_or+(text->lines_in_page*text->font_height)))
	<(rect [0].y + rect [0].height))
      rect [0].height = ny - rect [0].y;
    
    XSetClipRectangles ( dpy, text -> Cgc, 0, 0, rect, 1, False );
    TextCursorOff (text);
    XClearArea ( dpy, text -> window, text -> x_or, rect [0].y, 
		rect [0].width, rect [0].height, False );

    RefreshPage ( text );
    ClipOff ( text );
    TextCursorOn (text);
    if(tc_stat == OFF)
      TextCursorOff(text);
    if(tc_stat == FREEZE)
      FreezeTextCursor (text);
  }
  if (remove_bytes) {
/*    Clear_bytes(); */
    text -> selection -> select = False;
  }
}

/*
**	Function name : SelectionIsVisible
**
**	Description :
**	Input :
**	Output :
*/
int SelectionIsVisible(text)
    Text *text;
{
  if (text -> selection -> select == False) 
    return 0;

  return (text->selection->start_line <= text->selection->end_line)
    ? (! ((text->selection->end_line < (text->no_current_line - text->n1)) ||
	  (text->selection->start_line > (text->no_current_line + text->n2))))
    : (! ((text->selection->start_line < (text ->no_current_line - text->n1)) ||
	  (text->selection->end_line > (text->no_current_line + text->n2))));
}


/*
**	Function name : RefreshSelection
**
**	Description :
**	Input :
**	Output :
*/
void RefreshSelection(text)
    Text *text;
{
/*#define DEBUG5*/
  
  int i, li;
  XRectangle r [1];

  if (! SelectionIsVisible(text))
    return;

  TextCursorOff(text);
  
  for (i=0;i<8;i++) {
    rect[i].height = text -> font_height;
    rect[i].x = rect[i].y = rect[i].width = 0;
  }
  nrect = 0;

  if (text -> selection -> end_line != text -> selection -> start_line) {
    /* Selection sur plusieurs lignes */
#ifdef DEBUG5
    (void) fprintf (stderr, "51\n");
#endif /* DEBUG5 */
    /* Les 2 lignes extremes */
    (void) display_first_and_last (text);

    /* Les lignes intermediaires */
    rect[nrect].x = text -> x_or;
    if (text -> selection -> end_line > text -> selection -> start_line) {
      li = text -> no_current_line - text -> selection -> start_line;
      i = text -> selection -> end_line - text -> selection -> start_line -1;
    }
    else {
      li = text -> no_current_line - text -> selection -> end_line;
      i = text -> selection -> start_line - text -> selection -> end_line - 1;
    }
    
    rect[nrect].y = text -> y_or + ((text -> n1 - li + 1) * text -> font_height);
    rect[nrect].width = text -> width - (2 * text -> x_or);
    rect[nrect].height = i * text -> font_height;
    nrect++;
  }
  else {
    /* Selection sur une seule ligne */
    (void) display_one_line (text);
  }
  
#ifdef DEBUG5
    (void) fprintf (stderr, "57 i = %d\n", nrect);
#endif /* DEBUG5 */
  if (nrect) {
    r[0].x = text -> x_or;
    r[0].width = text -> width - ( 2 * text -> x_or );
    
    r[0].y = text -> y_or;
    r[0].height = text -> lines_in_page * text -> font_height;

    XSetClipRectangles ( dpy, sgc, 0, 0, r, 1, False );
    XFillRectangles (dpy, text -> window, sgc, rect, nrect);
    XSetClipMask ( dpy, sgc, None );

    for (i=0;i<8;i++) {
      rect[i].height = text -> font_height;
      rect[i].x = rect[i].y = rect[i].width = 0;
    }
  }
  TextCursorOn(text);
}

/*
**	Function name : display_on_line
**
**	Description :
**	Input :
**	Output :
*/
static void display_one_line(text)
    Text *text;
{
/* #define DEBUG6  */
  int i, nl;
  int s_nbc; /* nombre de caracteres de la selection */
  int s_nbc_vas; /* nombre de caracteres visibles avant la selection */
  
  /* Calcul du numero de ligne dans la page et de sa position en y */
  nl = text -> n1 - (text -> no_current_line - text -> selection -> start_line) + 1;
  rect[nrect].y = text -> y_or + ((nl -1) * text -> font_height);
#ifdef DEBUG6
  fprintf(stderr, "current = %d nl = %d y = %d\n",
	  text -> no_current_line, nl, rect[nrect].y);
#endif /* DEBUG6 */   
  if (select_run) {
    /* Scroll durant une selection. */
    text -> selection -> ncfl_el = GetNcFromLeft (text -> buf);    
  }
  if ((s_nbc = text -> selection -> ncfl_el - text -> selection -> ncfl_sl)>0) {
    /* Selection avec glissement vers la droite */
    if ((s_nbc_vas=(text -> selection -> ncfl_sl - text -> page.hs_dl[nl])) >= 0) {
      /* Debut de la selection visible ou cache a droite */
#ifdef DEBUG6
      (void) fprintf (stderr, "61\n");
#endif /* DEBUG6 */      
      rect[nrect].x = text -> x_or;
      if(text -> page.sline[nl]!=0 && s_nbc_vas > 0)
	rect[nrect].x += MyTextWidth (text, text -> page.sline[nl], s_nbc_vas);
      if (select_run)
	rect[nrect].width = text -> selection -> x_el - rect[nrect].x;
      else {
	if (text -> page.sline[nl]!=0)
	  rect[nrect].width = 
	    MyTextWidth (text, text -> page.sline[nl]+s_nbc_vas, s_nbc);
	else
	  rect[nrect].width = 0;
      }
    }
    else {
      /* Debut de la selection non visible */
#ifdef DEBUG6
      (void) fprintf (stderr, "62\n");
#endif /* DEBUG6 */      
      rect[nrect].x = text -> x_or;
      if (select_run)
	rect[nrect].width = text -> selection -> x_el - text -> x_or;
      else {
	if ((i = text -> selection -> ncfl_el - text -> page.hs_dl[nl])>0) {
	  if (text -> page.sline[nl]!=0)
	    rect[nrect].width = MyTextWidth (text, text -> page.sline[nl], i);
	  else
	    rect[nrect].width = 0;
	}
	else
	  rect[nrect].width = 0;
      }
    }
  }
  else {
    /* Selection avec glissement vers la gauche */
    s_nbc = -(s_nbc+1); /* le +1 c'est pour le curseur */
    if ((s_nbc_vas=(text -> selection -> ncfl_el - text -> page.hs_dl[nl]+1)) >= 0) {
      /* Fin de la selection visible ou cache droite */
#ifdef DEBUG6
      (void) fprintf (stderr, "63\n");
#endif /* DEBUG6 */      
      rect[nrect].x = text -> x_or;
      if(text -> page.sline[nl]!=0 && s_nbc_vas > 0)
	rect[nrect].x += MyTextWidth (text, text -> page.sline[nl], s_nbc_vas);
      if(text -> page.sline[nl]!=0 && s_nbc > 0)
	rect[nrect].width = 
	  MyTextWidth (text, text -> page.sline[nl]+s_nbc_vas, s_nbc);
      else
	rect[nrect].width = 0;
    }
    else {
     /* Fin de la selection non visible */
#ifdef DEBUG6
      (void) fprintf (stderr, "64\n");
#endif /* DEBUG6 */      
      rect[nrect].x = text -> x_or;
	if ((i = text -> selection -> ncfl_sl - text -> page.hs_dl[nl])>0) {
	  if (text -> page.sline[nl]!=0 && (s_nbc-i)>0)
	    rect[nrect].width = MyTextWidth (text, text -> page.sline[nl], s_nbc-i);
	  else
	    rect[nrect].width = 0;
	}
	else
	  rect[nrect].width = 0;
    }
  }
  nrect++;
}

/*
**	Function name : display_first_and_last
**
**	Description :
**	Input :
**	Output :
*/
static void display_first_and_last(text)
    Text *text;
{
/* #define DEBUG7 */
  int i, max, min , nl;
  
  max = text -> no_current_line + text -> n2;
  min = text -> no_current_line - text -> n1;
  if (select_run) {
    /* Scroll durant une selection. */
    text -> selection -> ncfl_el = GetNcFromLeft (text -> buf);    
  }
  
  if (text -> selection -> end_line > text -> selection -> start_line) {
    if ((text -> selection -> start_line >= min)
	&&(text -> selection -> start_line <= max)) {
#ifdef DEBUG7
      (void) fprintf (stderr, "71\n");
#endif /* DEBUG7 */
      /* Calcul du no de la premiere ligne de la selection dans la page courante */
      nl = text -> n1 - (text -> no_current_line - text -> selection -> start_line) + 1;
      rect[nrect].x = text -> x_or;
      if((text -> page.sline[nl]!=0)&&
	 ((text -> selection -> ncfl_sl - text -> page.hs_dl[nl])>0))
	rect[nrect].x += 
	  MyTextWidth (text, text -> page.sline[nl],
		       text -> selection -> ncfl_sl - text -> page.hs_dl[nl]);
      rect[nrect].width = text -> width - text -> x_or - rect[nrect].x;
      i=text -> no_current_line - text -> selection -> start_line;
      rect[nrect].y = text -> y_or + ((text -> n1 - i) * text -> font_height);
      nrect++;
    }
    if ((text -> selection -> end_line >= min)
	&&(text -> selection -> end_line <= max)) {	
#ifdef DEBUG7
      (void) fprintf (stderr, "72\n");
#endif /* DEBUG7 */
      /* Calcul du no de la derniere ligne de la selection dans la page courante */
      nl = text -> n1 - (text -> no_current_line - text -> selection -> end_line) + 1;
      rect[nrect].x = text -> x_or;
      if((text -> page.sline[nl]!=0)&&
	 ((text -> selection -> ncfl_el - text -> page.hs_dl[nl])>0))
	rect[nrect].width = 
	  MyTextWidth (text, text -> page.sline[nl],
		       text -> selection -> ncfl_el - text -> page.hs_dl[nl]);
      i=text -> no_current_line - text -> selection -> end_line;
      rect[nrect].y = text -> y_or + ((text -> n1 - i) * text -> font_height);
      nrect++;
    }
  }
  else {
      if ((text -> selection -> start_line >= min)
	&&(text -> selection -> start_line <= max)) {
	/* Calcul du no de la premiere ligne de la selection dans la page courante */
#ifdef DEBUG7
      (void) fprintf (stderr, "73\n");
#endif /* DEBUG7 */
	nl = text -> n1 - (text -> no_current_line - text -> selection -> start_line) + 1;
	rect[nrect].x = text -> x_or;
	if((text -> page.sline[nl]!=0)&&
	   ((text -> selection -> ncfl_sl - text -> page.hs_dl[nl])>0))
	  rect[nrect].width = 
	    MyTextWidth (text, text -> page.sline[nl],
			 text -> selection -> ncfl_sl - text -> page.hs_dl[nl]);
	else
	  rect[nrect].width = 0;
 	i=text -> no_current_line - text -> selection -> start_line;
	rect[nrect].y = text -> y_or + ((text -> n1 - i) * text -> font_height);
	nrect++;
	}
      if ((text -> selection -> end_line >= min)
	&&(text -> selection -> end_line <= max)) {	
#ifdef DEBUG7
      (void) fprintf (stderr, "74\n");
#endif /* DEBUG7 */
	/* Calcul du no de la derniere ligne de la selection dans la page courante */
	nl = text -> n1 - (text -> no_current_line - text -> selection -> end_line) + 1;
	rect[nrect].x = text -> x_or + text -> cursor_width;
	if((text -> page.sline[nl]!=0)&&
	   ((text -> selection -> ncfl_el - text -> page.hs_dl[nl])>0))
	  rect[nrect].x +=
	    MyTextWidth (text, text -> page.sline[nl],
			 text -> selection -> ncfl_el - text -> page.hs_dl[nl]);
	rect[nrect].width = text -> width - text -> x_or - rect[nrect].x;
 	i=text -> no_current_line - text -> selection -> end_line;
	rect[nrect].y = text -> y_or + ((text -> n1 - i) * text -> font_height);
	nrect++;
      }	
  }
}

/*
**	Function name : get_bytes_selection
**
**	Description :
**	Input :
**	Output :
*/
static void get_bytes_selection(text)
    Text *text;
{
/*#define DEBUG11*/
  int nl, nc;
  char *start, *p;
  
  if ((nl=text -> selection -> start_line - text -> selection -> end_line)==0) {
    if((nc=text -> selection -> ncfl_sl - text -> selection -> ncfl_el)==0) {
#ifdef DEBUG11
      (void) fprintf (stderr, "110 No selection\n");
#endif /* DEBUG11 */
      return;
    }
    else if (nc>0) {
#ifdef DEBUG11
      (void) fprintf (stderr, "111 s equal e, sl sup el\n");
#endif /* DEBUG11 */
      Store_bytes((char *)(RightBuf(text->buf)/*+1*/),nc/*-1*/);
    }
    else { /* nc<0 */
#ifdef DEBUG11
      (void) fprintf (stderr, "112 s equal e, sl inf el \n");
#endif /* DEBUG11 */
      Store_bytes((char *)(LeftBuf(text->buf)+nc+1), -nc);
    }
  }
  
  else if (nl>0){
    /* Selection vers le debut du buffer */
#ifdef DEBUG11
    (void) fprintf (stderr, "111 s sup e %c\n", (char *)RightBuf(text->buf)+1);
#endif /* DEBUG11 */
    nc = 0;
    start = RightBuf(text->buf);
    p = start;
    while(nl){
      if(*p=='\n')
	nl--;
      p++;
    }
/*    if(*start != '\n')
      start ++; */
    Store_bytes(start, p - start + text -> selection -> ncfl_sl);
  }
  
  else {/* nl<0 */
    /* Selection vers la fin du buffer */
#ifdef DEBUG11
    (void) fprintf (stderr, "112 s inf l\n");
#endif /* DEBUG11 */
    nl *= -1;
    start = LeftBuf(text->buf);
    p = start;
    nl++;
    while(nl && (p != TopBuf(text->buf))){
      if(*p=='\n') {
	nl--;
	if (nl == 0)
	  break;
      }
      p--;
    }
    if (p <= TopBuf(text->buf)) {
      p = TopBuf(text->buf);
      p += text -> selection -> ncfl_sl;
      Store_bytes(p, start - p + 1);
    }
    else {
      p += text -> selection -> ncfl_sl;
      Store_bytes(p + 1, start - p);
    }
  }
}

/*
**	Function name : StartSelection
**
**	Description :
**	Input :
**	Output :
*/
void StartSelection(text)
    Text *text;
{
  if (text -> selection -> select == True) {
    ClearSelection(text, True);
  }
  else {
    text -> selection -> start_line = text-> no_current_line;
    text -> selection -> ncfl_sl = GetNcFromLeft (text -> buf);
  }
}

/*
**	Function name : EndSelection
**
**	Description :
**	Input :
**	Output :
*/
void EndSelection(text)
    Text *text;
{
  text -> selection -> end_line = text-> no_current_line;
  text -> selection -> ncfl_el = GetNcFromLeft (text -> buf);
  text -> selection -> select = True;
}


/*
**	Function name : UpdateSelection
**
**	Description :
**	Input :
**	Output :
*/
void UpdateSelection(text)
    Text *text;
{
  int sl, el, current;
  int ncfl_sl, ncfl_el, pos, select = True;

  current = text -> no_current_line;
  sl = text -> selection -> start_line;
  el = text -> selection -> end_line;
  ncfl_sl = text -> selection -> ncfl_sl;
  ncfl_el = text -> selection -> ncfl_el;

  /* Pour mettre a jour la table des lignes */
  TextCursorOn(text);
  TextCursorOff(text);
  
  ClearSelection(text, True);
  
  if(sl<el) {
    if(current<=sl){
      text -> selection -> end_line = text-> no_current_line;
      text -> selection -> ncfl_el = GetNcFromLeft (text -> buf);
      text -> selection -> start_line = el;
      text -> selection -> ncfl_sl = ncfl_el;
    }
    else {
      text -> selection -> end_line = text-> no_current_line;
      text -> selection -> ncfl_el = GetNcFromLeft (text -> buf);
      text -> selection -> start_line = sl;
      text -> selection -> ncfl_sl = ncfl_sl;
    }
  }
  else if (sl>el) {
    if(current>=sl){
      text -> selection -> end_line = text-> no_current_line;
      text -> selection -> ncfl_el = GetNcFromLeft (text -> buf);
      text -> selection -> start_line = el;
      text -> selection -> ncfl_sl = ncfl_el;
    }
    else {
      text -> selection -> end_line = text-> no_current_line;
      text -> selection -> ncfl_el = GetNcFromLeft (text -> buf);
      text -> selection -> start_line = sl;
      text -> selection -> ncfl_sl = ncfl_sl;
    }
  }
  else {
    /* Selection sur une seule ligne */
    pos = GetNcFromLeft (text -> buf);
    if (current<sl) {
      /* position avant la ligne */
      if (ncfl_sl < ncfl_el) {
	text -> selection -> start_line = current;
	text -> selection -> end_line = sl;
	text -> selection -> ncfl_sl = pos + 1;
      }
      else {
	text -> selection -> end_line = current;
	text -> selection -> start_line = sl;
	text -> selection -> ncfl_el = pos + 1;
      }
    }
    else if (current>sl) {
      /* position apres la ligne */
      text -> selection -> start_line = sl;
      text -> selection -> end_line = current;
      if (ncfl_sl < ncfl_el) {
	text -> selection -> start_line = sl;
	text -> selection -> end_line = current;
	text -> selection -> ncfl_el = pos;
      }
      else {
	text -> selection -> start_line = current;
	text -> selection -> end_line = sl;
	text -> selection -> ncfl_sl = pos;
      }
    }
      
    else {
      /* position sur la ligne */
      if (pos == ncfl_sl || pos == ncfl_el)
	select = False;
      if (ncfl_sl < ncfl_el){
	if (pos<ncfl_el) 
	  text -> selection -> ncfl_sl = pos;
	else
	  text -> selection -> ncfl_el = pos;
      }
      else {
	if (pos<ncfl_sl)
	  text -> selection -> ncfl_el = pos;
	else
	  text -> selection -> ncfl_sl = pos;
      }
    }
  }
    
  if(select) {
    text -> selection -> select = True;
    (void) get_bytes_selection (text);
  }
}

/*
**	Function name : ClearSelectionIfNeeded
**
**	Description :
**	Input :
**	Output :
*/
void ClearSelectionIfNeeded(text)
    Text *text;
{
  extern int no_window;

  if (no_window == True)
    return;

  if (text->selection->select == True)
    ClearSelection(text, True);
}
