source: trunk/athena/lib/Xj/TextDisplay.c @ 12350

Revision 12350, 40.4 KB checked in by ghudson, 26 years ago (diff)
Some RCS ID cleanup: delete $Log$ and replace other RCS keywords with $Id$.
Line 
1/*
2 * $Id: TextDisplay.c,v 1.2 1999-01-22 23:17:02 ghudson Exp $
3 *
4 * Copyright 1990, 1991 by the Massachusetts Institute of Technology.
5 *
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#if  (!defined(lint))  &&  (!defined(SABER))
12static char rcsid[] =
13"$Id: TextDisplay.c,v 1.2 1999-01-22 23:17:02 ghudson Exp $";
14#endif
15
16#include "mit-copyright.h"
17#include <stdio.h>
18#include <string.h>
19#include <ctype.h>
20#include "Jets.h"
21#include "TextDisplay.h"
22#include "xselect.h"
23#include <X11/keysym.h>
24#include <X11/keysymdef.h>
25
26#define START True
27#define END False
28
29#define offset(field) XjOffset(TextDisplayJet,field)
30
31static XjResource resources[] = {
32  { XjNx, XjCX, XjRInt, sizeof(int),
33      offset(core.x), XjRString, XjInheritValue },
34  { XjNy, XjCY, XjRInt, sizeof(int),
35      offset(core.y), XjRString, XjInheritValue },
36  { XjNwidth, XjCWidth, XjRInt, sizeof(int),
37      offset(core.width), XjRString, XjInheritValue },
38  { XjNheight, XjCHeight, XjRInt, sizeof(int),
39      offset(core.height), XjRString, XjInheritValue },
40  { XjNdisplayWidth, XjCDisplayWidth, XjRInt, sizeof(int),
41      offset(textDisplay.displayWidth), XjRString, "80" },
42  { XjNdisplayHeight, XjCDisplayHeight, XjRInt, sizeof(int),
43      offset(textDisplay.displayHeight), XjRString, "5" },
44  { XjNtext, XjCText, XjRString, sizeof(char *),
45      offset(textDisplay.text), XjRString,""},
46  { XjNforeground, XjCForeground, XjRColor, sizeof(int),
47      offset(textDisplay.foreground), XjRString, XjDefaultForeground },
48  { XjNbackground, XjCBackground, XjRColor, sizeof(int),
49      offset(textDisplay.background), XjRString, XjDefaultBackground },
50  { XjNhighlightForeground, XjCForeground, XjRString, sizeof(char*),
51      offset(textDisplay.hl_fg_name), XjRString, "" },
52  { XjNhighlightBackground, XjCBackground, XjRString, sizeof(char*),
53      offset(textDisplay.hl_bg_name), XjRString, "" },
54  { XjNreverseVideo, XjCReverseVideo, XjRBoolean, sizeof(Boolean),
55      offset(textDisplay.reverseVideo), XjRBoolean, (caddr_t)False },
56  { XjNfont, XjCFont, XjRFontStruct, sizeof(XFontStruct *),
57      offset(textDisplay.font), XjRString, XjDefaultFont },
58  { XjNresizeProc, XjCResizeProc, XjRCallback, sizeof(XjCallback *),
59      offset(textDisplay.resizeProc), XjRString, NULL },
60  { XjNscrollProc, XjCScrollProc, XjRCallback, sizeof(XjCallback *),
61      offset(textDisplay.scrollProc), XjRString, NULL },
62  { XjNinternalBorder, XjCBorderWidth, XjRInt, sizeof(int),
63      offset(textDisplay.internalBorder), XjRString, "2" },
64  { XjNmultiClickTime, XjCMultiClickTime, XjRInt, sizeof(int),
65      offset(textDisplay.multiClickTime), XjRString, "250" },
66  { XjNcharClass, XjCCharClass, XjRString, sizeof(char *),
67      offset(textDisplay.charClass), XjRString, (caddr_t) NULL},
68  { XjNscrollDelay, XjCScrollDelay, XjRInt, sizeof(int),
69      offset(textDisplay.scrollDelay1), XjRString, "100" },
70  { XjNscrollDelay2, XjCScrollDelay, XjRInt, sizeof(int),
71      offset(textDisplay.scrollDelay2), XjRString, "50" },
72};
73
74#undef offset
75
76static void initialize(), expose(), realize(), querySize(), move(),
77  destroy(), resize(), appendLines(), drawChars();
78static Boolean event_handler();
79
80TextDisplayClassRec textDisplayClassRec = {
81  {
82    /* class name */            "TextDisplay",
83    /* jet size   */            sizeof(TextDisplayRec),
84    /* classInitialize */       NULL,
85    /* classInitialized? */     1,
86    /* initialize */            initialize,
87    /* prerealize */            NULL,
88    /* realize */               realize,
89    /* event */                 event_handler,
90    /* expose */                expose,
91    /* querySize */             querySize,
92    /* move */                  move,
93    /* resize */                resize,
94    /* destroy */               destroy,
95    /* resources */             resources,
96    /* number of 'em */         XjNumber(resources)
97  }
98};
99
100JetClass textDisplayJetClass = (JetClass)&textDisplayClassRec;
101
102     /* The "charClass" table below, and the functions */
103     /* "SetCharacterClassRange" and "set_character_class" following it */
104     /* are taken from the xterm sources, and as such are subject to the */
105     /* copyright included here...:    */
106
107/*
108 * Copyright 1988 Massachusetts Institute of Technology
109 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
110 *
111 *                         All Rights Reserved
112 *
113 * Permission to use, copy, modify, and distribute this software and its
114 * documentation for any purpose and without fee is hereby granted,
115 * provided that the above copyright notice appear in all copies and that
116 * both that copyright notice and this permission notice appear in
117 * supporting documentation, and that the name of Digital Equipment
118 * Corporation not be used in advertising or publicity pertaining to
119 * distribution of the software without specific, written prior permission.
120 *
121 *
122 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
123 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
124 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
125 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
126 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
127 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
128 * SOFTWARE.
129 */
130
131/*
132** double click table for cut and paste in 8 bits
133**
134** This table is divided in four parts :
135**
136**      - control characters    [0,0x1f] U [0x80,0x9f]
137**      - separators            [0x20,0x3f] U [0xa0,0xb9]
138**      - binding characters    [0x40,0x7f] U [0xc0,0xff]
139**      - execeptions
140*/
141static int charClass[256] = {
142/* NUL  SOH  STX  ETX  EOT  ENQ  ACK  BEL */
143    32,   1,   1,   1,   1,   1,   1,   1,
144/*  BS   HT   NL   VT   NP   CR   SO   SI */
145     1,  32,   1,   1,   1,   1,   1,   1,
146/* DLE  DC1  DC2  DC3  DC4  NAK  SYN  ETB */
147     1,   1,   1,   1,   1,   1,   1,   1,
148/* CAN   EM  SUB  ESC   FS   GS   RS   US */
149     1,   1,   1,   1,   1,   1,   1,   1,
150/*  SP    !    "    #    $    %    &    ' */
151    32,  33,  34,  35,  36,  37,  38,  39,
152/*   (    )    *    +    ,    -    .    / */
153    40,  41,  42,  43,  44,  45,  46,  47,
154/*   0    1    2    3    4    5    6    7 */
155    48,  48,  48,  48,  48,  48,  48,  48,
156/*   8    9    :    ;    <    =    >    ? */
157    48,  48,  58,  59,  60,  61,  62,  63,
158/*   @    A    B    C    D    E    F    G */
159    64,  48,  48,  48,  48,  48,  48,  48,
160/*   H    I    J    K    L    M    N    O */
161    48,  48,  48,  48,  48,  48,  48,  48,
162/*   P    Q    R    S    T    U    V    W */
163    48,  48,  48,  48,  48,  48,  48,  48,
164/*   X    Y    Z    [    \    ]    ^    _ */
165    48,  48,  48,  91,  92,  93,  94,  48,
166/*   `    a    b    c    d    e    f    g */
167    96,  48,  48,  48,  48,  48,  48,  48,
168/*   h    i    j    k    l    m    n    o */
169    48,  48,  48,  48,  48,  48,  48,  48,
170/*   p    q    r    s    t    u    v    w */
171    48,  48,  48,  48,  48,  48,  48,  48,
172/*   x    y    z    {    |    }    ~  DEL */
173    48,  48,  48, 123, 124, 125, 126,   1,
174/* x80  x81  x82  x83  IND  NEL  SSA  ESA */
175     1,   1,   1,   1,   1,   1,   1,   1,
176/* HTS  HTJ  VTS  PLD  PLU   RI  SS2  SS3 */
177     1,   1,   1,   1,   1,   1,   1,   1,
178/* DCS  PU1  PU2  STS  CCH   MW  SPA  EPA */
179     1,   1,   1,   1,   1,   1,   1,   1,
180/* x98  x99  x9A  CSI   ST  OSC   PM  APC */
181     1,   1,   1,   1,   1,   1,   1,   1,
182/*   -    i   c/    L   ox   Y-    |   So */
183   160, 161, 162, 163, 164, 165, 166, 167,
184/*  ..   c0   ip   <<    _        R0    - */
185   168, 169, 170, 171, 172, 173, 174, 175,
186/*   o   +-    2    3    '    u   q|    . */
187   176, 177, 178, 179, 180, 181, 182, 183,
188/*   ,    1    2   >>  1/4  1/2  3/4    ? */
189   184, 185, 186, 187, 188, 189, 190, 191,
190/*  A`   A'   A^   A~   A:   Ao   AE   C, */
191    48,  48,  48,  48,  48,  48,  48,  48,
192/*  E`   E'   E^   E:   I`   I'   I^   I: */
193    48,  48,  48,  48,  48,  48,  48,  48,
194/*  D-   N~   O`   O'   O^   O~   O:    X */
195    48,  48,  48,  48,  48,  48,  48, 216,
196/*  O/   U`   U'   U^   U:   Y'    P    B */
197    48,  48,  48,  48,  48,  48,  48,  48,
198/*  a`   a'   a^   a~   a:   ao   ae   c, */
199    48,  48,  48,  48,  48,  48,  48,  48,
200/*  e`   e'   e^   e:    i`  i'   i^   i: */
201    48,  48,  48,  48,  48,  48,  48,  48,
202/*   d   n~   o`   o'   o^   o~   o:   -: */
203    48,  48,  48,  48,  48,  48,  48,  248,
204/*  o/   u`   u'   u^   u:   y'    P   y: */
205    48,  48,  48,  48,  48,  48,  48,  48};
206
207int SetCharacterClassRange (low, high, value)
208    register int low, high;             /* in range of [0..255] */
209    register int value;                 /* arbitrary */
210{
211
212    if (low < 0 || high > 255 || high < low) return (-1);
213
214    for (; low <= high; low++) charClass[low] = value;
215
216    return (0);
217}
218
219
220/*
221 * set_character_class - takes a string of the form
222 *
223 *                 low[-high]:val[,low[-high]:val[...]]
224 *
225 * and sets the indicated ranges to the indicated values.
226 */
227
228int set_character_class (s)
229    register char *s;
230{
231    register int i;                     /* iterator, index into s */
232    int len;                            /* length of s */
233    int acc;                            /* accumulator */
234    int low, high;                      /* bounds of range [0..127] */
235    int base;                           /* 8, 10, 16 (octal, decimal, hex) */
236    int numbers;                        /* count of numbers per range */
237    int digits;                         /* count of digits in a number */
238    static char *errfmt = "%s in range string \"%s\" (position %d)\n";
239    char errtext[100];
240
241    if (!s || !s[0]) return -1;
242
243    base = 10;                          /* in case we ever add octal, hex */
244    low = high = -1;                    /* out of range */
245
246    for (i = 0, len = strlen (s), acc = 0, numbers = digits = 0;
247         i < len; i++) {
248        char c = s[i];
249
250        if (isspace(c)) {
251            continue;
252        } else if (isdigit(c)) {
253            acc = acc * base + (c - '0');
254            digits++;
255            continue;
256        } else if (c == '-') {
257            low = acc;
258            acc = 0;
259            if (digits == 0) {
260                sprintf (errtext, errfmt, "missing number", s, i);
261                XjWarning(errtext);
262                return (-1);
263            }
264            digits = 0;
265            numbers++;
266            continue;
267        } else if (c == ':') {
268            if (numbers == 0)
269              low = acc;
270            else if (numbers == 1)
271              high = acc;
272            else {
273                sprintf (errtext, errfmt, "too many numbers", s, i);
274                XjWarning(errtext);
275                return (-1);
276            }
277            digits = 0;
278            numbers++;
279            acc = 0;
280            continue;
281        } else if (c == ',') {
282            /*
283             * now, process it
284             */
285
286            if (high < 0) {
287                high = low;
288                numbers++;
289            }
290            if (numbers != 2) {
291                sprintf (errtext, errfmt, "bad value number", s, i);
292                XjWarning(errtext);
293            } else if (SetCharacterClassRange (low, high, acc) != 0) {
294                sprintf (errtext, errfmt, "bad range", s, i);
295                XjWarning(errtext);
296            }
297
298            low = high = -1;
299            acc = 0;
300            digits = 0;
301            numbers = 0;
302            continue;
303        } else {
304            sprintf (errtext, errfmt, "bad character", s, i);
305            XjWarning(errtext);
306            return (-1);
307        }                               /* end if else if ... else */
308
309    }
310
311    if (low < 0 && high < 0) return (0);
312
313    /*
314     * now, process it
315     */
316
317    if (high < 0) high = low;
318    if (numbers < 1 || numbers > 2) {
319        sprintf (errtext, errfmt, "bad value number", s, i);
320        XjWarning(errtext);
321    } else if (SetCharacterClassRange (low, high, acc) != 0) {
322        sprintf (errtext, errfmt, "bad range", s, i);
323        XjWarning(errtext);
324    }
325
326    return (0);
327}
328     /* The "charClass" table above, and the functions */
329     /* "SetCharacterClassRange" and "set_character_class" following it */
330     /* are taken from the xterm sources, and as such are subject to the */
331     /* copyright included above. */
332
333
334
335
336static void initialize(me)
337     TextDisplayJet me;
338{
339  me->textDisplay.realized = 0;
340
341  me->textDisplay.charWidth = me->textDisplay.font->max_bounds.width;
342  me->textDisplay.charHeight = (me->textDisplay.font->ascent
343                                + me->textDisplay.font->descent);
344
345  me->textDisplay.lineStartsSize = 1000;
346  me->textDisplay.lineStarts = (char **)XjMalloc(1000 * sizeof(char *));
347  me->textDisplay.startSelect = 0;
348  me->textDisplay.endSelect = 0;
349  me->textDisplay.realStart = 0;
350  me->textDisplay.realEnd = 0;
351  me->textDisplay.selection = NULL;
352  me->textDisplay.clickTimes = 0;
353  me->textDisplay.buttonDown = False;
354
355  /*
356   * Initialize the first lines for safety...  trust me...
357   * (it's in case there's no text in the jet and someone tries to do a
358   *  multi-click to select some text...  it also keeps "appendLines"
359   *  from breaking...)
360   */
361  me->textDisplay.lineStarts[0] = "";
362
363  set_character_class(me->textDisplay.charClass);
364  xselInitAtoms(me->core.display);
365}
366
367/*
368 * Things are currently broken screenwise.
369 * It will be fun to fix later. :)
370 */
371static void realize(me)
372     TextDisplayJet me;
373{
374  unsigned long valuemask, valuemask2;
375  unsigned long pixel;
376  XGCValues values;
377
378  if (me->textDisplay.reverseVideo)
379    {
380      int swap = me->textDisplay.foreground;
381      me->textDisplay.foreground = me->textDisplay.background;
382      me->textDisplay.background = swap;
383    }
384
385  if (strcmp(me->textDisplay.hl_fg_name, "")
386      &&  !StrToXPixel(XjDisplay(me), me->textDisplay.hl_fg_name, &pixel))
387    me->textDisplay.hl_foreground = pixel;
388  else
389    me->textDisplay.hl_foreground = me->textDisplay.background;
390
391  if (strcmp(me->textDisplay.hl_bg_name, "")
392      &&  !StrToXPixel(XjDisplay(me), me->textDisplay.hl_bg_name, &pixel))
393    me->textDisplay.hl_background = pixel;
394  else
395    me->textDisplay.hl_background = me->textDisplay.foreground;
396
397  values.function = GXcopy;
398  values.font = me->textDisplay.font->fid;
399  values.foreground = me->textDisplay.foreground;
400  values.background = me->textDisplay.background;
401  valuemask = GCForeground | GCBackground | GCFont | GCFunction;
402  me->textDisplay.gc = XjCreateGC(me->core.display,
403                                  me->core.window,
404                                  valuemask,
405                                  &values);
406
407  values.foreground = values.background;
408  valuemask2 = GCForeground | GCFunction;
409  me->textDisplay.gc_clear = XjCreateGC(me->core.display,
410                                        me->core.window,
411                                        valuemask2,
412                                        &values);
413
414
415  values.foreground = ((me->textDisplay.foreground
416                        == me->textDisplay.hl_foreground)
417                       ? me->textDisplay.background
418                       : me->textDisplay.hl_foreground);
419  values.background = ((me->textDisplay.background
420                        == me->textDisplay.hl_background)
421                       ? me->textDisplay.foreground
422                       : me->textDisplay.hl_background);
423  valuemask = GCForeground | GCBackground | GCFont | GCFunction;
424  me->textDisplay.selectgc = XjCreateGC(me->core.display,
425                                        me->core.window,
426                                        valuemask,
427                                        &values);
428
429  values.foreground = values.background;
430  valuemask2 = GCForeground | GCFunction;
431  me->textDisplay.gc_fill = XjCreateGC(me->core.display,
432                                       me->core.window,
433                                       valuemask2,
434                                       &values);
435
436  me->textDisplay.visLines = (me->core.height -
437                              2 * me->textDisplay.internalBorder) /
438                                me->textDisplay.charHeight;
439
440  /*
441   * Usurp events for this window
442   */
443  XjRegisterWindow(me->core.window, (Jet) me);
444  XjSelectInput(me->core.display, me->core.window,
445                ButtonPressMask | ButtonReleaseMask
446                | ButtonMotionMask | KeyPressMask );
447
448  me->textDisplay.realized = 1;
449}
450
451static void destroy(me)
452     TextDisplayJet me;
453{
454  XjFreeGC(me->core.display, me->textDisplay.gc);
455  XjFreeGC(me->core.display, me->textDisplay.selectgc);
456  XjFreeGC(me->core.display, me->textDisplay.gc_fill);
457  XjFreeGC(me->core.display, me->textDisplay.gc_clear);
458
459  XjUnregisterWindow(me->core.window, (Jet) me);
460}
461
462static void querySize(me, size)
463     TextDisplayJet me;
464     XjSize *size;
465{
466  size->width = me->textDisplay.displayWidth * me->textDisplay.charWidth +
467    2 * me->textDisplay.internalBorder;
468  size->height = me->textDisplay.displayHeight * me->textDisplay.charHeight +
469    2 * me->textDisplay.internalBorder;
470}
471
472static void move(me, x, y)
473     TextDisplayJet me;
474     int x, y;
475{
476  me->core.x = x;
477  me->core.y = y;
478}
479
480static void resize(me, size)
481     TextDisplayJet me;
482     XjSize *size;
483{
484  me->core.width = size->width;
485  me->core.height = size->height;
486  me->textDisplay.visLines = (me->core.height -
487                              2 * me->textDisplay.internalBorder) /
488                                me->textDisplay.charHeight;
489  me->textDisplay.columns = (me->core.width -
490                             2 * me->textDisplay.internalBorder) /
491                               me->textDisplay.charWidth;
492  if (me->textDisplay.realized)
493    appendLines(me, me->textDisplay.text, 0);
494}
495
496static void drawLine(me, line, y)
497     TextDisplayJet me;
498     int line, y;
499{
500  int c = 0, length;
501  char *ptr, *end, *last;
502
503  ptr = me->textDisplay.lineStarts[line];
504  last = me->textDisplay.lineStarts[line + 1];
505
506  while (ptr != last)
507    {
508      end = ptr;
509
510      while (end < last && *end != '\t')
511        end++;
512
513      length = end - ptr;
514
515      if (length != 0)
516        {
517          XDrawString(me->core.display, me->core.window,
518                      me->textDisplay.gc,
519                      me->core.x + me->textDisplay.internalBorder +
520                      c * me->textDisplay.charWidth,
521                      y + me->textDisplay.font->ascent,
522                      ptr, length - (ptr[length - 1] == '\n'));
523          c += length;
524        }
525
526      if (end < last && *end == '\t') /* could be reduced, but... */
527        {
528          c = 8 * ((c / 8) + 1);
529          end++;
530          length++;
531          while (end < last && *end == '\t')
532            {
533              end++;
534              length++;
535              c += 8;
536            }
537        }
538           
539      ptr += length;
540    }
541}
542
543static void drawText(me, start, num, y)
544     TextDisplayJet me;
545     int start;
546     int num, y;
547{
548  char *first, *last;
549
550  first = me->textDisplay.lineStarts[start];
551  last = me->textDisplay.lineStarts[MIN(start + num,
552                                           me->textDisplay.numLines)];
553
554 
555  if (me->textDisplay.startSelect == me->textDisplay.endSelect ||
556      last <= me->textDisplay.startSelect ||
557      first >= me->textDisplay.endSelect)
558    {
559      while (num != 0 && start < me->textDisplay.numLines)
560        {
561          drawLine(me, start, y);
562          start++;
563          num--;
564          y += me->textDisplay.charHeight;
565        }
566/*
567      drawChars(me, me->textDisplay.gc, first, last);
568*/
569      return;
570    }
571
572  /*
573   * Since we're here, there must be some selected text drawn.
574   */
575  if (first <= me->textDisplay.startSelect) /* last > startSelect */
576    {
577      drawChars(me, me->textDisplay.gc,
578                first, me->textDisplay.startSelect);
579      first = me->textDisplay.startSelect;
580    }
581
582  drawChars(me, me->textDisplay.selectgc,
583            first, MIN(me->textDisplay.endSelect, last));
584
585  if (last > me->textDisplay.endSelect)
586    drawChars(me, me->textDisplay.gc,
587              me->textDisplay.endSelect, last);
588}
589
590static void drawSome(me, gc, y, startOfLine, start, last)
591     TextDisplayJet me;
592     GC gc;
593     int y;
594     char *startOfLine, *start, *last;
595{
596  int c = 0, length;
597  char *ptr, *end;
598
599/*  fprintf(stdout, "%d\n", gc == me->textDisplay.selectgc); */
600  /*
601   * At the end of this while, c is the column number to start
602   * drawing at, and ptr is start.
603   */
604  ptr = startOfLine;
605  while (ptr != start)
606    {
607      end = ptr;
608
609      while (end < start && *end != '\t')
610        end++;
611
612      length = end - ptr;
613      c += length;
614
615      if (end < start && *end == '\t') /* could be reduced, but... */
616        {
617          c = 8 * ((c / 8) + 1);
618          end++;
619          length++;
620          while (end < start && *end == '\t')
621            {
622              end++;
623              length++;
624              c += 8;
625            }
626        }
627           
628      ptr += length;
629    }
630
631  while (ptr != last)
632    {
633      end = ptr;
634
635      while (end < last && *end != '\t')
636        end++;
637
638      length = end - ptr;
639
640      if (length != 0)
641        {
642          XDrawImageString(me->core.display, me->core.window,
643                           gc,
644                           me->core.x + me->textDisplay.internalBorder +
645                           c * me->textDisplay.charWidth,
646                           y + me->textDisplay.font->ascent,
647                           ptr, length - (ptr[length - 1] == '\n'));
648/*        fprintf(stdout, "%.*s",  length - (ptr[length - 1] == '\n'),
649                  ptr);
650          fflush(stdout); */
651          c += length;
652
653          /* this is gross... */
654          if (ptr[length-1] == '\n')
655            {
656              int tmp = (c-1) * me->textDisplay.charWidth +
657                me->textDisplay.internalBorder;
658
659              XFillRectangle(me->core.display, me->core.window,
660                             ((gc == me->textDisplay.selectgc)
661                              ? me->textDisplay.gc_fill
662                              : me->textDisplay.gc_clear),
663                             me->core.x + tmp,
664                             y,
665                             MAX(0, (me->textDisplay.columns + 1 - c)
666                                 * me->textDisplay.charWidth),
667                             (me->textDisplay.font->ascent +
668                              me->textDisplay.font->descent));
669            }
670        }
671
672      if (end < last && *end == '\t') /* could be reduced, but... */
673        {
674          XDrawImageString(me->core.display, me->core.window,
675                           gc,
676                           me->core.x + me->textDisplay.internalBorder +
677                           c * me->textDisplay.charWidth,
678                           y + me->textDisplay.font->ascent,
679                           "        ", 8 - (c%8));
680/*        fprintf(stdout, "%.*s", 8-(c%8), "        ");
681          fflush(stdout); */
682          c = 8 * ((c / 8) + 1);
683          end++;
684          length++;
685          while (end < last && *end == '\t')
686            {
687              XDrawImageString(me->core.display, me->core.window,
688                               gc,
689                               me->core.x + me->textDisplay.internalBorder +
690                               c * me->textDisplay.charWidth,
691                               y + me->textDisplay.font->ascent,
692                               "        ", 8);
693              end++;
694              length++;
695              c += 8;
696/*            fprintf(stdout, "        ");
697              fflush(stdout); */
698            }
699        }
700           
701      ptr += length;
702    }
703}
704
705static void drawChars(me, gc, start, end)
706     TextDisplayJet me;
707     GC gc;
708     char *start, *end;
709{
710  int y;
711  int line;
712
713  for (line = me->textDisplay.topLine;
714       line < me->textDisplay.topLine + me->textDisplay.visLines &&
715       line < me->textDisplay.numLines;
716       line++)
717    if (me->textDisplay.lineStarts[line + 1] > start)
718      break;
719
720  if (me->textDisplay.lineStarts[line] > start)
721    start = me->textDisplay.lineStarts[line];
722
723  if (start >= end)
724    return;
725
726  if (line >= me->textDisplay.topLine + me->textDisplay.visLines ||
727      line >= me->textDisplay.numLines)
728    return;
729
730  y = me->core.y + me->textDisplay.internalBorder +
731    (line - me->textDisplay.topLine) * me->textDisplay.charHeight;
732
733  for (;line < me->textDisplay.topLine + me->textDisplay.visLines &&
734       line < me->textDisplay.numLines; line++)
735    {
736      drawSome(me, gc, y, me->textDisplay.lineStarts[line],
737               start,
738               MIN(me->textDisplay.lineStarts[line + 1], end));
739      y += me->textDisplay.charHeight;
740      start = me->textDisplay.lineStarts[line + 1];
741      if (start > end)
742        break;
743    }
744}
745
746static void drawCharacters(me, start, end)
747     TextDisplayJet me;
748     char *start, *end;
749{
750  if (start < me->textDisplay.startSelect)
751    {
752      if (end <= me->textDisplay.startSelect)
753        {
754          drawChars(me, me->textDisplay.gc, start, end);
755          return;
756        }
757
758      drawChars(me, me->textDisplay.gc,
759                start,
760                me->textDisplay.startSelect);
761      start = me->textDisplay.startSelect;
762    }
763
764  if (start < me->textDisplay.endSelect)
765    {
766      if (end <= me->textDisplay.endSelect)
767        {
768          drawChars(me, me->textDisplay.selectgc, start, end);
769          return;
770        }
771
772      drawChars(me, me->textDisplay.selectgc,
773                start,
774                me->textDisplay.endSelect);
775      start = me->textDisplay.endSelect;
776    }
777
778  drawChars(me, me->textDisplay.gc, start, end);
779}
780
781/*
782 * This draws only the regions of text whose selected
783 * state has changed.
784 */
785static void showSelect(me, selStart, selEnd)
786     TextDisplayJet me;
787     char *selStart, *selEnd;
788{
789  int i, j;
790  char *k, *s[4];
791
792  s[0] = selStart;
793  s[1] = selEnd;
794  s[2] = me->textDisplay.startSelect;
795  s[3] = me->textDisplay.endSelect;
796
797  /* sort the array into order. */
798  for (i = 0; i < 3; i++)
799    for (j = i + 1; j < 4; j++)
800      if (s[i] > s[j])
801        {
802          k = s[i];
803          s[i] = s[j];
804          s[j] = k;
805        }
806
807  if (s[0] != s[1])
808    drawCharacters(me, s[0], s[1]);
809
810  if (s[2] != s[3])
811    drawCharacters(me, s[2], s[3]);
812}
813
814
815static int timerid = -1;
816
817void auto_scroll(me, id)
818     TextDisplayJet me;
819     int id;                    /* ARGSUSED */
820{
821  Window junkwin;
822  int x, y, junk;
823  unsigned int junkmask;
824  XEvent event;
825
826  timerid = -1;
827
828  XQueryPointer(XjDisplay(me), XjWindow(me),
829                &junkwin, &junkwin, &junk, &junk, &x, &y, &junkmask);
830
831  event.type = MotionNotify;    /* Fake out the event_handler into */
832  event.xbutton.x = x;          /* thinking that the mouse has moved. */
833  event.xbutton.y = y;          /* It will then deal with selecting and */
834  event_handler(me, &event);    /* scrolling more, as needed. */
835}
836
837
838char *where(me, x, y, line)
839     TextDisplayJet me;
840     int x, y;
841     int *line;
842{
843  char *ptr, *end;
844  int col, tmp, vert, c = 0;
845  int clickTimes = me->textDisplay.clickTimes % 5;
846#define LINE *line
847 
848  if (me->textDisplay.numLines == 0)
849    {
850      LINE = 0;
851      return me->textDisplay.lineStarts[0];
852    }
853
854  vert = (y - me->core.y - me->textDisplay.internalBorder);
855  LINE = ((y - me->core.y - me->textDisplay.internalBorder) /
856          me->textDisplay.charHeight) + me->textDisplay.topLine;
857  col = ((x - me->core.x - me->textDisplay.internalBorder) /
858         me->textDisplay.charWidth);
859
860  /*
861   * Deal with autoscrolling...  first check if we want to scroll up...
862   */
863  if (vert < -20  &&  me->textDisplay.topLine > 0
864      &&  timerid == -1
865      &&  (me->textDisplay.scrollDelay1 >= 0 ||
866           me->textDisplay.scrollDelay2 >= 0))
867    {
868      SetLine(me, me->textDisplay.topLine - 1);
869      XjCallCallbacks(me, me->textDisplay.scrollProc, NULL);
870
871      timerid = XjAddWakeup(auto_scroll, me,
872                            (vert < -40  &&
873                             me->textDisplay.scrollDelay2 >= 0)
874                            ? me->textDisplay.scrollDelay2
875                            : me->textDisplay.scrollDelay1);
876    }
877
878  /* bounds checking */
879  if (LINE < me->textDisplay.topLine)
880    LINE = me->textDisplay.topLine;
881#ifdef notdef
882  if (LINE < 0)                 /* is this really necessary??? */
883    LINE = 0;
884#endif
885  if (vert < -40)
886    return me->textDisplay.lineStarts[LINE];
887
888  /*
889   * ...now check if we're past the last line, and the last line is
890   *  *not* at the bottom of the jet...  if this is the case, then we
891   *  want to return the end of the text...
892   */
893  if (LINE > me->textDisplay.numLines
894      &&  me->textDisplay.visLines > me->textDisplay.numLines)
895    {
896      LINE = me->textDisplay.numLines;
897      return me->textDisplay.lineStarts[me->textDisplay.numLines];
898    }
899
900  /*
901   * ...then check if we want to scroll down...
902   */
903  tmp = me->textDisplay.topLine + me->textDisplay.visLines;
904  if (LINE >= tmp)
905    LINE = tmp - 1;
906
907  if (vert - me->core.height > 20  &&  tmp < me->textDisplay.numLines
908      &&  timerid == -1
909      &&  (me->textDisplay.scrollDelay1 >= 0 ||
910           me->textDisplay.scrollDelay2 >= 0))
911    {
912      SetLine(me, me->textDisplay.topLine + 1); /* scroll down... */
913      XjCallCallbacks(me, me->textDisplay.scrollProc, NULL);
914      LINE += 1;
915
916      timerid = XjAddWakeup(auto_scroll, me,
917                            (vert - me->core.height > 40  &&
918                             me->textDisplay.scrollDelay2 >= 0)
919                            ? me->textDisplay.scrollDelay2
920                            : me->textDisplay.scrollDelay1);
921    }
922
923  /* bounds checking */
924#ifdef notdef
925  if (LINE == me->textDisplay.numLines - 1)
926    {
927#endif
928      if (vert - me->core.height > 40)
929        return me->textDisplay.lineStarts[LINE + 1];
930#ifdef notdef
931    }
932#endif
933  if (LINE >= me->textDisplay.numLines)
934    LINE = me->textDisplay.numLines - 1;
935
936
937  ptr = me->textDisplay.lineStarts[LINE];
938  end = me->textDisplay.lineStarts[LINE + 1];
939
940  while (c < col && ptr < end)
941    {
942      while ((c < col) && *ptr != '\t' && ptr < end)
943        {
944          ptr++;
945          c++;
946        }
947
948      if ((c < col) && ptr < end && *ptr == '\t')
949        {
950          c = 8 * ((c / 8) + 1);
951          ptr++;
952
953          while ((c < col) && *ptr == '\t' && ptr < end)
954            {
955              c += 8;
956              ptr++;
957            }
958        }
959    }
960
961  if (clickTimes == 1)
962    return ptr;
963
964#ifdef notdef
965  if (me->textDisplay.columns <= col)   /* to deal with dragging off the */
966    return ptr;                         /* right edge */       
967#endif
968  if (ptr == end)
969    ptr = end - 1;
970
971  return ptr;
972
973#undef LINE
974}
975
976char *find_boundary(me, ptr, line, find_start)
977     TextDisplayJet me;
978     char **ptr;
979     int line;
980     Boolean find_start;
981{
982  int clickTimes = me->textDisplay.clickTimes % 5;
983
984  if (me->textDisplay.numLines == 0)
985    return *ptr;
986
987  if (clickTimes == 1)          /* single-clicks - select by char */
988    return *ptr;
989
990  if (clickTimes == 2)          /* double-clicks - select by "word" */
991    {
992      char *tmp;
993     
994      if (find_start)
995        {
996          tmp = *ptr - 1;
997          while(tmp >= me->textDisplay.lineStarts[0] &&
998                charClass[*tmp] == charClass[**ptr])
999            tmp--;
1000          tmp++;
1001        }
1002      else
1003        {
1004          tmp = *ptr;
1005          while(tmp <= me->textDisplay.lineStarts[me->textDisplay.numLines] &&
1006                charClass[*tmp] == charClass[**ptr])
1007            tmp++;
1008        }
1009      return tmp;
1010    }
1011
1012  if (clickTimes == 3)          /* triple-clicks - select by "line" */
1013    return me->textDisplay.lineStarts[(find_start)
1014                                      ? line
1015                                      : MIN(me->textDisplay.numLines,
1016                                            line + 1)];
1017
1018  if (clickTimes == 4)          /* quad-clicks - select by "paragraph" */
1019    {
1020      char *tmp;
1021      int blankline, x;
1022
1023      if (find_start)
1024        {
1025          /*
1026           *  scan backward to the beginning of the "paragraph"
1027           */
1028          for (x = line;
1029               x >= 0;
1030               x--)
1031            {
1032              blankline = True;
1033              if (x < me->textDisplay.numLines)
1034                for (tmp = me->textDisplay.lineStarts[x];
1035                     blankline && tmp <= (me->textDisplay.lineStarts[x+1] - 1);
1036                     tmp++)
1037                  if (*tmp != ' '  && *tmp != '\t' &&
1038                      *tmp != '\n' && *tmp != '\0')
1039                    blankline = False;
1040
1041              if (blankline)
1042                return me->textDisplay.lineStarts[(x == line) ? x : x+1];
1043            }
1044          return me->textDisplay.lineStarts[0];
1045        }
1046
1047      else
1048        {
1049          /*
1050           *  scan forward to the end of the "paragraph"
1051           */
1052          for (x = line;
1053               x < me->textDisplay.numLines;
1054               x++)
1055            {
1056              blankline = True;
1057              for (tmp = me->textDisplay.lineStarts[x];
1058                   blankline && tmp <= (me->textDisplay.lineStarts[x+1] - 1);
1059                   tmp++)
1060                if (*tmp != ' '  && *tmp != '\t' &&
1061                    *tmp != '\n' && *tmp != '\0')
1062                  blankline = False;
1063
1064              if (blankline)
1065                return me->textDisplay.lineStarts[(x == line) ? x+1 : x];
1066            }
1067          return me->textDisplay.lineStarts[x];
1068        }
1069    }
1070
1071                                /* quint-clicks - select all text */
1072  return me->textDisplay.lineStarts[(find_start)
1073                                    ? 0 : me->textDisplay.numLines];
1074}
1075
1076
1077static void expose(me, event)
1078     Jet me;
1079     XEvent *event;             /* ARGSUSED */
1080{
1081  drawText((TextDisplayJet) me,
1082           ((TextDisplayJet) me)->textDisplay.topLine,
1083           ((TextDisplayJet) me)->textDisplay.visLines,
1084           me->core.y + ((TextDisplayJet) me)->textDisplay.internalBorder);
1085}
1086
1087static void appendLines(me, text, num)
1088     TextDisplayJet me;
1089     char *text;
1090     int num;
1091{
1092  int c, col;
1093  char *top = me->textDisplay.lineStarts[me->textDisplay.topLine];
1094
1095  if (me->textDisplay.columns < 1 ||
1096      text == NULL)
1097    return;
1098
1099  while (*text != '\0')
1100    {
1101      /* The +2 is a useful hack. */
1102      if (num + 2 > me->textDisplay.lineStartsSize)
1103        {
1104          me->textDisplay.lineStarts =
1105            (char **)XjRealloc(me->textDisplay.lineStarts,
1106                               (1000 + me->textDisplay.lineStartsSize)
1107                               * sizeof(char *));
1108          me->textDisplay.lineStartsSize += 1000;
1109        }
1110
1111      me->textDisplay.lineStarts[num] = text;
1112      if (text == top)
1113        me->textDisplay.topLine = num;
1114
1115      col = 0;
1116      for (c = 0; col < me->textDisplay.columns; c++)
1117        switch(text[c])
1118          {
1119          case '\0':
1120            c--;
1121          case '\n':
1122            col = me->textDisplay.columns;
1123            break;
1124          case '\t':
1125            col = 8 * ((col / 8) + 1);
1126            break;
1127          default:
1128            col++;
1129            break;
1130          }
1131      text += c;
1132      if (/* text > me->textDisplay.text && not necessary */
1133          text[0] == '\n' && text[-1] != '\n') /* then wrapped */
1134        text++; /* stupid to <cr> here */
1135
1136      num++;
1137    }
1138
1139  me->textDisplay.lineStarts[num] = text;
1140  me->textDisplay.numLines = num;
1141  if (text == top)
1142    me->textDisplay.topLine = num;
1143
1144  if (me->textDisplay.realized)
1145    XjCallCallbacks(me, me->textDisplay.resizeProc, NULL);
1146}
1147
1148void showNewLines(me, start)
1149     TextDisplayJet me;
1150     int start;
1151{
1152  if (start >= me->textDisplay.topLine &&
1153      start <= (me->textDisplay.topLine + me->textDisplay.visLines - 1))
1154    drawText(me,
1155             start,
1156             me->textDisplay.topLine + me->textDisplay.visLines - start,
1157             me->core.y + me->textDisplay.internalBorder +
1158             (start - me->textDisplay.topLine) *
1159             me->textDisplay.charHeight);
1160}
1161
1162void AddText(me)
1163     TextDisplayJet me;
1164{
1165  int l;
1166
1167  l = me->textDisplay.numLines;
1168  if (l > 0)  l--;
1169  appendLines(me, me->textDisplay.lineStarts[l], l);
1170  if (me->textDisplay.realized)
1171    showNewLines(me, l);
1172}
1173
1174void MoveText(me, text, offset)
1175     TextDisplayJet me;
1176     char *text;
1177     int offset;
1178{
1179  me->textDisplay.startSelect = (char *)
1180    MAX((int) text, (int) me->textDisplay.startSelect - offset);
1181  me->textDisplay.endSelect = (char *)
1182    MAX((int) text, (int) me->textDisplay.endSelect - offset);
1183  me->textDisplay.realStart = (char *)
1184    MAX((int) text, (int) me->textDisplay.realStart - offset);
1185  me->textDisplay.realEnd = (char *)
1186    MAX((int) text, (int) me->textDisplay.realEnd - offset);
1187
1188  me->textDisplay.text = text;
1189  me->textDisplay.topLine = 0;
1190
1191  appendLines(me, text, 0);
1192  if (me->textDisplay.realized)
1193    XClearArea(me->core.display, me->core.window,
1194               me->core.x, me->core.y,
1195               me->core.width, me->core.height, True);
1196}
1197
1198void SetText(me, text)
1199     TextDisplayJet me;
1200     char *text;
1201{
1202  me->textDisplay.startSelect = text;
1203  me->textDisplay.endSelect = text;
1204  me->textDisplay.realStart = text;
1205  me->textDisplay.realEnd = text;
1206
1207  MoveText(me, text, 0);
1208}
1209
1210int TopLine(me)
1211     TextDisplayJet me;
1212{
1213  return me->textDisplay.topLine;
1214}
1215
1216int VisibleLines(me)
1217     TextDisplayJet me;
1218{
1219  return me->textDisplay.visLines;
1220}
1221
1222int CountLines(me)
1223     TextDisplayJet me;
1224{
1225  return me->textDisplay.numLines;
1226}
1227
1228#define abs(x) (((x) < 0) ? (-(x)) : (x))
1229
1230void SetLine(me, value)
1231     TextDisplayJet me;
1232     int value;
1233{
1234  int diff, charHeight;
1235
1236  if (value == me->textDisplay.topLine)
1237    return;
1238
1239  charHeight = me->textDisplay.charHeight;
1240
1241  diff = value - me->textDisplay.topLine;
1242  if (diff > 0 &&
1243      diff < me->textDisplay.visLines)
1244    { /* scroll */
1245      XCopyArea(me->core.display,
1246                me->core.window,
1247                me->core.window,
1248                me->textDisplay.gc,
1249                me->core.x,
1250                me->core.y + me->textDisplay.internalBorder +
1251                diff * charHeight,
1252                me->core.width,
1253                (me->textDisplay.visLines - diff) * charHeight,
1254                me->core.x,
1255                me->core.y + me->textDisplay.internalBorder);
1256
1257      XClearArea(me->core.display,
1258                 me->core.window,
1259                 me->core.x,
1260                 me->core.y + me->textDisplay.internalBorder +
1261                 (me->textDisplay.visLines - diff) * charHeight,
1262                 me->core.width,
1263                 diff * charHeight,
1264                 False);
1265
1266      me->textDisplay.topLine = value;
1267
1268      drawText(me,
1269               value + me->textDisplay.visLines - diff,
1270               diff,
1271               me->core.y + me->textDisplay.internalBorder +
1272               (me->textDisplay.visLines - diff) * charHeight);
1273    }
1274  else
1275    if (diff < 0 &&
1276        (-diff) < me->textDisplay.visLines)
1277      {
1278        /* scroll */
1279        diff = -diff;
1280       
1281        XCopyArea(me->core.display,
1282                  me->core.window,
1283                  me->core.window,
1284                  me->textDisplay.gc,
1285                  me->core.x,
1286                  me->core.y + me->textDisplay.internalBorder,
1287                  me->core.width,
1288                  (me->textDisplay.visLines - diff) * charHeight,
1289                  me->core.x,
1290                  me->core.y + me->textDisplay.internalBorder +
1291                  diff * charHeight);
1292
1293        XClearArea(me->core.display,
1294                   me->core.window,
1295                   me->core.x,
1296                   me->core.y + me->textDisplay.internalBorder,
1297                   me->core.width,
1298                   diff * charHeight,
1299                   False);
1300     
1301        me->textDisplay.topLine = value;
1302
1303        drawText(me,
1304                 me->textDisplay.topLine,
1305                 diff,
1306                 me->core.y + me->textDisplay.internalBorder);
1307      }
1308  else
1309    { /* completely new screen... */
1310      XClearArea(me->core.display,
1311                 me->core.window,
1312                 me->core.x,
1313                 me->core.y,
1314                 me->core.width,
1315                 me->core.height,
1316                 False);
1317
1318      me->textDisplay.topLine = value;
1319
1320      drawText(me,
1321               me->textDisplay.topLine,
1322               me->textDisplay.visLines,
1323               me->core.y + me->textDisplay.internalBorder);
1324    }
1325}
1326
1327static Boolean event_handler(me, event)
1328     TextDisplayJet me;
1329     XEvent *event;
1330{
1331  char *w;
1332  int line;
1333  char *oldStart, *oldEnd;
1334  int length;
1335
1336  oldStart = me->textDisplay.startSelect;
1337  oldEnd = me->textDisplay.endSelect;
1338
1339  switch(event->type)
1340    {
1341    case KeyPress:
1342      switch (XLookupKeysym(&(event->xkey), 0))
1343        {
1344        case XK_Left:
1345        case XK_Up:
1346          if (me->textDisplay.topLine > 0)
1347            SetLine(me, me->textDisplay.topLine - 1);
1348          break;
1349
1350        case XK_Right:
1351        case XK_Down:
1352          if (me->textDisplay.topLine + me->textDisplay.visLines
1353              < me->textDisplay.numLines)
1354            SetLine(me, me->textDisplay.topLine + 1);
1355          break;
1356
1357        case XK_R9:             /* "PgUp" on the Sun kbd. */
1358        case XK_Prior:
1359          {
1360            int tmp = me->textDisplay.topLine - (me->textDisplay.visLines - 1);
1361            SetLine(me, MAX(0, tmp));
1362          }
1363          break;
1364
1365        case XK_R15:            /* "PgDn" on the Sun kbd. */
1366        case XK_Next:
1367          if (me->textDisplay.numLines > me->textDisplay.visLines)
1368            {
1369              int tmp = me->textDisplay.topLine + me->textDisplay.visLines - 1;
1370              int tmp2 = me->textDisplay.numLines - me->textDisplay.visLines;
1371              SetLine(me, MIN(tmp, tmp2));
1372            }
1373          break;
1374
1375        case XK_R7:             /* "Home" on the Sun kbd. */
1376        case XK_Home:
1377          SetLine(me, 0);
1378          break;
1379
1380        case XK_R13:            /* "End" on the Sun kbd. */
1381        case XK_End:
1382          if (me->textDisplay.numLines > me->textDisplay.visLines)
1383            SetLine(me, me->textDisplay.numLines - me->textDisplay.visLines);
1384          break;
1385
1386        default:
1387          return False;
1388        }
1389
1390      XjCallCallbacks(me, me->textDisplay.scrollProc, NULL);
1391      break;
1392
1393    case ButtonRelease:
1394      if (me->textDisplay.buttonDown == False)
1395        break;
1396      me->textDisplay.buttonDown = False;
1397
1398      if (event->xbutton.button == Button1)
1399        me->textDisplay.lastUpTime = event->xbutton.time;
1400
1401      me->textDisplay.realStart = me->textDisplay.startSelect;
1402      me->textDisplay.realEnd = me->textDisplay.endSelect;
1403
1404      if (me->textDisplay.startSelect == me->textDisplay.endSelect)
1405        break;
1406
1407      if (xselGetOwnership(me->core.display, /* bug! */
1408                           me->core.window,
1409                           event->xbutton.time))
1410        {
1411          length = (int)(me->textDisplay.realEnd -
1412                         me->textDisplay.realStart);
1413          if (me->textDisplay.selection != NULL)
1414            XjFree(me->textDisplay.selection);
1415          me->textDisplay.selection = (char *)XjMalloc(length + 1);
1416          memcpy(me->textDisplay.selection,
1417                me->textDisplay.realStart, length);
1418          me->textDisplay.selection[length] = '\0';
1419        }
1420      break;
1421
1422    case ButtonPress:
1423      if (me->textDisplay.buttonDown == True)
1424        break;
1425
1426      /* MUST compute clickTimes before calling "where" below, as the */
1427      /* return values from it depend on the value of clickTime... */
1428
1429      if (event->xbutton.button == Button1)
1430        {
1431          if (me->textDisplay.clickTimes != 0
1432              && event->xbutton.time - me->textDisplay.lastUpTime
1433              < me->textDisplay.multiClickTime)
1434            me->textDisplay.clickTimes++;
1435          else
1436            me->textDisplay.clickTimes = 1;
1437        }
1438
1439      /* deal with button3 being first one pushed... */
1440      if (event->xbutton.button == Button3
1441          &&  me->textDisplay.clickTimes == 0)
1442        me->textDisplay.clickTimes = 1;
1443
1444      me->textDisplay.buttonDown = True;
1445      me->textDisplay.whichButton = event->xbutton.button;
1446      w = where(me, event->xbutton.x, event->xbutton.y, &line);
1447
1448      switch(me->textDisplay.whichButton)
1449        {
1450        case Button1:
1451          me->textDisplay.startSelect = me->textDisplay.startPivot =
1452            find_boundary(me, &w, line, START);
1453          me->textDisplay.endSelect = me->textDisplay.endPivot =
1454            find_boundary(me, &w, line, END);
1455          break;
1456
1457        case Button3:
1458          if ((int)w <
1459              ((int)me->textDisplay.realStart +
1460               (int)me->textDisplay.realEnd)
1461              / 2)
1462            {
1463              me->textDisplay.startEnd = 0;
1464              me->textDisplay.startSelect = find_boundary(me, &w, line, START);
1465              me->textDisplay.endSelect = me->textDisplay.realEnd;
1466            }
1467          else
1468            {
1469              me->textDisplay.startEnd = 1;
1470              me->textDisplay.endSelect = find_boundary(me, &w, line, END);
1471              me->textDisplay.startSelect = me->textDisplay.realStart;
1472            }
1473          break;
1474        }
1475
1476      showSelect(me, oldStart, oldEnd);
1477      break;
1478
1479    case MotionNotify:
1480      /* sigh... Xqvss can't be trusted, due to kernel bug */
1481      if (me->textDisplay.buttonDown == False)
1482        break;
1483
1484      w = where(me, event->xbutton.x, event->xbutton.y, &line);
1485
1486      switch(me->textDisplay.whichButton)
1487        {
1488        case Button1:
1489          me->textDisplay.startSelect = me->textDisplay.startPivot;
1490          me->textDisplay.endSelect = me->textDisplay.endPivot;
1491
1492          if (w >= me->textDisplay.endPivot)
1493            me->textDisplay.endSelect = find_boundary(me, &w, line, END);
1494          else if (w < me->textDisplay.startPivot)
1495            me->textDisplay.startSelect = find_boundary(me, &w, line, START);
1496          break;
1497
1498        case Button3:
1499          if (w > me->textDisplay.realEnd)
1500            {
1501              me->textDisplay.startEnd = 1;
1502              me->textDisplay.endSelect = find_boundary(me, &w, line, END);
1503              me->textDisplay.startSelect = me->textDisplay.realStart;
1504            }
1505          else if (w < me->textDisplay.realStart)
1506            {
1507              me->textDisplay.startEnd = 0;
1508              me->textDisplay.startSelect = find_boundary(me, &w, line, START);
1509              me->textDisplay.endSelect = me->textDisplay.realEnd;
1510            }
1511          else if (me->textDisplay.startEnd == 0)
1512            me->textDisplay.startSelect = find_boundary(me, &w, line, START);
1513          else
1514            me->textDisplay.endSelect = find_boundary(me, &w, line, END);
1515          break;
1516        }
1517      showSelect(me, oldStart, oldEnd);
1518      break;
1519
1520    case SelectionRequest:
1521      xselProcessSelection(me->core.display, me->core.window, event,
1522                           me->textDisplay.selection);
1523      break;
1524
1525    case SelectionClear:
1526      xselOwnershipLost(event->xselectionclear.time);
1527      me->textDisplay.endSelect = me->textDisplay.startSelect;
1528      showSelect(me, oldStart, oldEnd);
1529      if (me->textDisplay.selection != NULL)
1530        {
1531          XjFree(me->textDisplay.selection);
1532          me->textDisplay.selection = NULL;
1533        }
1534      break;
1535
1536    default:
1537      return False;
1538    }
1539
1540  return True;
1541}
Note: See TracBrowser for help on using the repository browser.