Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimSelect.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$TOG: TermPrimSelect.c /main/6 1999/10/14 16:22:53 mgreess $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company               *
31  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.                *
33  * (c) Copyright 1993, 1994, 1996 Novell, Inc.                          *
34  * (c) Copyright 1995, 1996 Digital Equipment Corporation.              *
35  * (c) Copyright 1996 FUJITSU LIMITED.                                  *
36  * (c) Copyright 1996 Hitachi.                                          *
37  */
38
39 #include "TermHeader.h"
40 #include <X11/Xatom.h>
41 #include <Xm/Xm.h>
42 #include <Xm/AtomMgr.h>
43 #include <Xm/CutPaste.h>
44 #include <Xm/ScrollBarP.h>
45 #include "TermPrimDebug.h"
46 #include "TermPrimP.h"
47 #include "TermPrimData.h"
48 #include "TermPrimRender.h"
49 #include "TermPrimSelectP.h"
50 #include "TermPrimBufferP.h"
51 #include <Xm/DropSMgr.h>
52 #include <Xm/DropTrans.h>
53
54 #if defined(USL)
55 #include <ctype.h>
56 #include <wctype.h>
57 #endif
58
59 /* This is for Sun's two button mouse */
60
61 static char _DtTermEventBindingsCDE[] = "\
62 ~c ~s ~m ~a <Btn1Down>:process-press(grab-focus,process-bdrag)\n\
63 ~c s ~m ~a <Btn1Down>:process-press(extend-start,process-bdrag)\n\
64 ~c ~m ~a <Btn1Motion>:select-adjust()\n\
65 ~c ~m ~a <Btn1Up>:extend-end()";
66 static char _DtTermEventBindingsCDEBtn2[] = "\
67 <Btn2Down>:extend-start()\n\
68 <Btn2Motion>:select-adjust()\n\
69 <Btn2Up>:extend-end()";
70
71 static
72 XmTextScanType defaultScanArray[] =
73 {
74     XmSELECT_POSITION,
75     XmSELECT_WORD,
76     XmSELECT_LINE,
77     XmSELECT_ALL
78 };
79
80 static void RegisterDropSite( Widget w );
81 static void doExtendedSelection (Widget  w,Time  eventTime);
82
83 /* 
84 ** Get the current server time (I ripped this off from Xm/TextIn.c).
85 */
86 static Time
87 getServerTime
88 (
89      Widget w
90 )
91 {
92     XEvent    event;
93     EventMask shellMask;
94     
95     while(!XtIsShell(w))
96     {
97         w = XtParent(w);
98     }
99
100     shellMask = XtBuildEventMask(w);
101
102     if (!(shellMask & PropertyChangeMask))
103     {
104        XSelectInput(XtDisplay(w), XtWindow(w), shellMask | PropertyChangeMask);
105     }
106
107     XChangeProperty(XtDisplay(w), XtWindow(w), XA_WM_HINTS, XA_WM_HINTS,
108                     32, PropModeAppend, (unsigned char *)NULL, 0);
109
110     XWindowEvent(XtDisplay(w), XtWindow(w), PropertyChangeMask, &event);
111
112     if (!(shellMask & PropertyChangeMask))
113     {
114        XSelectInput(XtDisplay(w), XtWindow(w), shellMask);
115     }
116
117     return(event.xproperty.time);
118 }
119
120
121 static void
122 setScanType
123 (
124     Widget  w,
125     XEvent *event
126 )
127 {
128     TermSelectInfo  selectInfo = 
129                     ((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
130     int             multiClickTime;
131     int             i;
132
133     multiClickTime = XtGetMultiClickTime(XtDisplay(w));
134
135     if (event->xbutton.time > selectInfo->lastTime &&
136         event->xbutton.time - selectInfo->lastTime <
137                          (multiClickTime == 200 ? 500 : multiClickTime))
138     {
139         i = 0;
140         while (i < selectInfo->scanArraySize && 
141                selectInfo->scanArray[i] != selectInfo->scanType)
142         {
143             i++;
144         }
145
146         if (++i >= selectInfo->scanArraySize)
147         {
148             i = 0;
149         }
150         selectInfo->scanType = selectInfo->scanArray[i];
151     } 
152     else
153     {   
154         /* single-click event */
155         selectInfo->scanType = selectInfo->scanArray[0];
156     }
157     
158     selectInfo->lastTime = event->xbutton.time;
159 }
160
161 /* 
162 ** convert a row,col pair into the equivalent XmTextPosition
163 ** 
164 ** NOTE: 
165 **     this routine assumes that the calling routine as already checked
166 **     row and col to insure that they are within the bounds of the terminal
167 **     buffer (see _DtTermPrimSelectGrabFocus)
168 */
169 XmTextPosition
170 rowColToPos
171 (
172     DtTermPrimitiveWidget   tw,
173     short                   row,
174     short                   col
175 )
176 {
177     DtTermPrimData  tpd = tw->term.tpd;
178
179     return(((tpd->selectInfo->columns + 1) * 
180             (row + tpd->lastUsedHistoryRow)) + col);
181 }
182
183 /* 
184 ** getSelection
185 */
186 Boolean
187 _DtTermPrimSelectGetSelection
188 (
189     Widget          w,
190     XmTextPosition *begin,
191     XmTextPosition *end
192 )
193 {
194     TermSelectInfo  selectInfo = 
195                     ((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
196
197     if (selectInfo->ownPrimary && 
198         (selectInfo->begin <= selectInfo->end) &&
199         selectInfo->begin >= 0)
200     {
201         *begin = selectInfo->begin;
202         *end   = selectInfo->end;
203         return(True);
204     }
205     else
206     {
207         *begin = 0;
208         *end   = 0;
209         selectInfo->ownPrimary = False;
210         return(False);
211     }
212 }    
213
214
215 /* 
216 ** convert an x,y pair into the appropriate text position
217 ** 
218 ** Since positions count the number of inter-character spaces, there is
219 ** one more x position on a line than columns on a line; xPos can be in
220 ** the range (0, selectInfo->columns + 1).  The same is true for yPos,
221 ** it can be in the range (0, tpd->lastUsedRow - tpd->topRow - 1)
222 **
223 ** In the case that we have a history buffer to deal with, text positions
224 ** in the history buffer are forced to come before positions in the term
225 ** buffer.
226 **
227 ** NOTE: 
228 **     this routine assumes that the calling routine as already checked
229 **     x and y to insure that they are within the bounds of the terminal
230 **     window (see _DtTermPrimSelectGrabFocus)
231 ** NOTE: 
232 **     I believe I'm now doing all checking in this routine for confining
233 **     the x,y to the window.  Disregard the previous note. TMH
234 */
235 static 
236 XmTextPosition
237 xyToPos
238 (
239     DtTermPrimitiveWidget   tw,
240     int                     x,                /* pixel */
241     int                     y                 /* pixel */
242 )
243 {
244     DtTermPrimData  tpd        = tw->term.tpd;
245     TermSelectInfo  selectInfo = tpd->selectInfo;
246     TermBuffer      tb;
247     short           row;
248     short           yPos;
249     short           xPos;
250     static short    oldYPos = -1;
251     static short    oldXPos = -1;
252     
253
254     if ( x<0) x = 0;  
255     if ( x > (int) tw->core.width) x = tw->core.width;  
256     /* 
257     ** convert pixel units to character positions
258     */
259     yPos = (MAX(0, y) - tpd->offsetY) / tpd->cellHeight;
260     
261     /* 
262     ** yPos cannot exceed the buffer or screen
263     */
264     yPos = MIN(yPos, MIN(tw->term.rows, tpd->lastUsedRow - tpd->topRow) - 1) +
265            tpd->topRow;
266
267     /* 
268     ** consider the possibility that we have a history buffer
269     */
270     if (tpd->useHistoryBuffer)
271     {
272         if (yPos < 0)
273         {
274             /* 
275             ** yPos is not in the history buffer (order is important,
276             ** step 2 must come before step 3):
277             **    1) point to history buffer
278             **    2) adjust yPos
279             **    3) decide which row of the buffer we are concerned
280             **       with
281             */
282             tb  = tpd->historyBuffer;
283             yPos += tpd->lastUsedHistoryRow;
284             row = yPos;
285         }
286         else
287         {
288             /* 
289             ** yPos is not in the history buffer (order is important,
290             ** step 2 must come before step 3):
291             **    1) point to term buffer
292             **    2) decide which row of the buffer we are concerned
293             **       with
294             **    3) adjust yPos
295             */
296             tb  = tpd->termBuffer;        
297             row = yPos;    
298             yPos += tpd->lastUsedHistoryRow;            
299         }
300     }
301     else
302     {
303         tb   = tpd->termBuffer;        
304         row  = yPos; 
305     }
306
307     xPos = (((x - tpd->offsetX) + (tpd->cellWidth / 2)) / tpd->cellWidth) ;
308
309     if ( MB_CUR_MAX > 1 )  /* check if xPos splits a 2 col char */
310      {      
311        TermCharInfoRec charInfoRec ;
312        if (_DtTermPrimGetCharacterInfo(tb,row,xPos,&charInfoRec) )
313          {
314             if (charInfoRec.width == 2 && charInfoRec.startCol != xPos)
315               {
316                 if (xPos*tpd->cellWidth < x - tpd->offsetX )
317                    xPos++ ;  /* set to right of char */
318                 else
319                    xPos-- ;  /* set to left of char */
320               }
321          }
322      }
323     
324         
325     if ((yPos != oldYPos) || (xPos != oldXPos))
326     {
327         oldYPos = yPos;
328         oldXPos = xPos;
329     }
330     return (((selectInfo->columns + 1) * yPos) + xPos);
331 }
332
333 /*
334  * Takes a linear position and return buffer, row, and col.
335  * Since positions are between characters, this returns the col to
336  * right of the position.
337  */
338 static void
339 posToBufferRowCol
340 (
341     DtTermPrimitiveWidget  tw,
342     XmTextPosition pos,
343     TermBuffer *pb,
344     short *row,
345     short *col
346 )
347 {
348     DtTermPrimData   tpd        = tw->term.tpd;
349     TermSelectInfo   selectInfo = tpd->selectInfo;
350     short lrow, lcol;
351
352     lrow = pos / (selectInfo->columns + 1);
353     lcol = pos - (lrow * (selectInfo->columns + 1));
354
355     if ( tpd->useHistoryBuffer ) lrow -= tpd->lastUsedHistoryRow ;  
356
357     if ( lrow < 0 )  {   /* in history buffer */
358        *pb=tw->term.tpd->historyBuffer ;
359        lrow += tpd->lastUsedHistoryRow ; 
360      }
361     else
362      {
363        *pb = tpd->termBuffer ;
364      }
365     *row = lrow ;
366     *col = lcol ;
367 }
368
369 /*
370  * Takes a buffer, row and column and returns the linear position.
371  */
372 static XmTextPosition
373 bufferRowColToPos
374 (
375     DtTermPrimitiveWidget  tw,
376     TermBuffer pb,
377     short row,
378     short col
379 )
380 {
381     DtTermPrimData   tpd        = tw->term.tpd;
382     TermSelectInfo   selectInfo = tpd->selectInfo;
383     short lrow, lcol;
384     XmTextPosition pos;
385
386     /* assume row, col in the history buffer or there is no history */
387     pos = (tpd->selectInfo->columns + 1) * row + col;
388
389     if ( tpd->useHistoryBuffer && pb == tpd->termBuffer)   
390       pos += (tpd->selectInfo->columns + 1) * (tpd->lastUsedHistoryRow) ;
391     return(pos) ;
392 }
393    
394
395 static XmTextPosition
396 scan
397 (
398     DtTermPrimitiveWidget   tw,
399     XmTextPosition          scanStart, 
400     XmTextScanType          scanType,
401     TermScanDirection       scanDir,
402     int                     count,
403     Boolean                 inclusive
404 )
405 {
406     int              i;
407     DtTermPrimData   tpd        = tw->term.tpd;
408     TermSelectInfo   selectInfo = tpd->selectInfo;
409     XmTextPosition   position   = scanStart;
410     short            row;
411     short            col;
412     TermBuffer pb ;
413     
414
415     switch(scanType)
416     {
417       case XmSELECT_POSITION:
418         posToBufferRowCol(tw, position, &pb, &row, &col) ;
419         if ( col  > _DtTermPrimBufferGetLineWidth(pb, row) )
420          {
421             col  = selectInfo->columns + 1;
422             position = bufferRowColToPos(tw,pb,row,col) ;
423          }
424         break;
425       case XmSELECT_WORD:
426        {
427         short width;
428         posToBufferRowCol(tw, position, &pb, &row, &col) ;
429         width = _DtTermPrimBufferGetLineWidth(pb,row);
430         if ( col > width ) break;
431
432         if (  MB_CUR_MAX > 1 ) 
433           {
434             TermCharInfoRec charInfoRec ;
435
436             _DtTermPrimGetCharacterInfo(pb,row,col,&charInfoRec);
437             col = charInfoRec.startCol ;  /* align first */
438
439             switch(scanDir)
440             {
441               case scanLeft:
442                 _DtTermPrimGetCharacterInfo(pb,row,col?--col:0,&charInfoRec);
443                 while( !iswspace(*(wchar_t *)charInfoRec.u.pwc) &&
444                                        ((col=charInfoRec.startCol-1)>=0) )
445                  {
446                    _DtTermPrimGetCharacterInfo(pb,row,col,&charInfoRec) ;
447                  }
448                 col ++ ;
449                 break;
450               case scanRight:
451                 _DtTermPrimGetCharacterInfo(pb,row,col,&charInfoRec);
452                 while(++col<=width  && !iswspace(*(wchar_t *)charInfoRec.u.pwc))
453                    _DtTermPrimGetCharacterInfo(pb,row,col,&charInfoRec);
454                 col--;
455                 break;
456              }
457           }
458         else
459           {
460             char pbuf[10];
461             switch(scanDir)
462             {
463               case scanLeft:
464                 _DtTermPrimBufferGetText(pb, row, col?--col:0, 1, pbuf, False);
465                 while( !isspace(*pbuf) && --col >= 0)
466                    _DtTermPrimBufferGetText(pb, row, col, 1, pbuf, False );
467                 col++ ;
468                 break;
469               case scanRight:
470                 _DtTermPrimBufferGetText(pb, row, col, 1, pbuf, False);
471                 while( ++col <= width && !isspace(*pbuf))
472                    _DtTermPrimBufferGetText(pb, row, col, 1, pbuf, False );
473                 col--;
474                 break;
475              }
476            }
477          position = bufferRowColToPos(tw,pb,row,col) ;
478         }
479         break;
480       case XmSELECT_LINE:
481        {
482         
483         posToBufferRowCol(tw, position, &pb, &row, &col) ;
484         col = 0;
485         switch(scanDir)
486         {
487           case scanLeft:
488             break;
489           case scanRight:
490             col =  selectInfo->columns + 1;
491             break;
492         }
493         position = bufferRowColToPos(tw,pb,row,col) ;
494        }
495        break;
496       case XmSELECT_ALL:
497         switch(scanDir)
498         {
499           case scanLeft:
500             position = 0;
501             break;
502           case scanRight:
503             pb  = tpd->termBuffer ;
504             row = tpd->lastUsedRow-1;
505             col = _DtTermPrimBufferGetLineWidth(pb,row) ;
506             position = bufferRowColToPos(tw,pb,row,col) ;
507             break;
508         }
509         break;
510     }
511     return(position);
512 }
513
514 /* 
515 ** refresh all text from start up to stop
516 ** 
517 ** NOTE: 
518 **     We assume that start is always <= than stop
519 */
520 void
521 _DtTermPrimRenderRefreshTextLinear
522 (
523     Widget          w,
524     XmTextPosition  start,
525     XmTextPosition  stop
526 )
527 {
528     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget) w;
529     DtTermPrimData          tpd        = tw->term.tpd;
530     TermSelectInfo          selectInfo = tpd->selectInfo;
531     short                   startRow, startCol;
532     short                   stopRow , stopCol;
533     
534
535     /* 
536     ** Turn XmTextPosition into a row and column
537     */
538     startRow = start / (selectInfo->columns + 1);
539     startCol = start - (startRow * (selectInfo->columns + 1));
540     stopRow  = stop / (selectInfo->columns + 1);
541     stopCol  = stop - (stopRow * (selectInfo->columns + 1));
542     
543     /* 
544     ** Accomodate the history buffer as necessary
545     */
546     if (tpd->useHistoryBuffer)
547     {
548         startRow -= tpd->lastUsedHistoryRow;
549         stopRow  -= tpd->lastUsedHistoryRow;
550     }
551
552     /* 
553     ** Now adjust for the top of the window
554     */
555     startRow -= tpd->topRow;
556     stopRow  -= tpd->topRow;
557     
558
559     /*
560     ** refresh the first (and possibly only) line
561     */
562     if (startRow == stopRow)
563     {
564         _DtTermPrimRefreshText((Widget)tw, startCol, startRow, 
565                                stopCol, startRow);
566         return;
567     }
568     _DtTermPrimRefreshText((Widget)tw, startCol, startRow, 
569                       selectInfo->columns - 1, startRow);
570     
571     /* 
572     ** refresh the middle block (if there is one)
573     */
574     if (startRow++ < stopRow)
575     {
576         _DtTermPrimRefreshText((Widget)tw, 0, startRow, 
577                          selectInfo->columns - 1, stopRow - 1);
578     }
579
580     /* 
581     ** refresh the last line 
582     */
583     _DtTermPrimRefreshText((Widget)tw, 0, stopRow, stopCol, stopRow);
584     
585 }
586
587
588 static void
589 setSelection
590 (
591     DtTermPrimitiveWidget   tw,
592     XmTextPosition          begin, 
593     XmTextPosition          end,
594     Time                    selectTime,
595     Boolean                 fromLoseSelection
596 )
597 {
598     TermSelectInfo  selectInfo = tw->term.tpd->selectInfo;
599     XmTextPosition  oldBegin, oldEnd;
600     Boolean         disJoint;       /* true if new and current are disjoint */
601     short           selectLineBegin;
602     short           selectColBegin;
603     short           selectLineEnd;
604     short           selectColEnd;
605
606     Debug('c', fprintf(stderr, ">>setSelection() starting\n"));
607
608     if (selectInfo->ownPrimary == False &&
609         begin > end)
610     {
611         Debug('c', fprintf(stderr, ">>setSelection() finishing a\n"));
612         return;
613     }    
614
615     if (begin < 0)
616     {
617         begin = 0;
618         end   = 0;
619     }
620     
621     if (selectInfo->ownPrimary)
622     {
623         /* 
624         ** we own the selection see how much (if any) of the selected
625         ** area needs to be unhighlighted...
626         */
627         if (selectInfo->begin < selectInfo->end)
628         {
629             /* 
630             ** We own the selection, and its highlighted...
631             */
632             if ((end <= selectInfo->begin) ||
633                 (begin >= selectInfo->end))
634             {
635                 /* 
636                 ** The two areas don't intersect, simply clear the old
637                 ** area...
638                 */
639                 Debug('c', fprintf(stderr, "    new & old are disjoint\n"));
640                 selectInfo->ownPrimary = False;
641                 _DtTermPrimRenderRefreshTextLinear((Widget)tw, 
642                                                    selectInfo->begin,
643                                                    selectInfo->end - 1);
644                 selectInfo->ownPrimary = True;
645                 disJoint = True;
646             }
647             else
648             {
649                 /* 
650                 ** There is some intersection, save the current begin
651                 ** and end so we can clean things up later.
652                 */
653                 Debug('c', fprintf(stderr, "    new & old intersect\n"));
654                 oldBegin = selectInfo->begin;
655                 oldEnd   = selectInfo->end;
656                 disJoint = False;
657             }
658         }
659         else
660         {
661             /* 
662             ** We own the selection, but nothing is highlighted...
663             */
664             disJoint = True;
665         }
666     }
667     else
668     {
669         /* 
670         ** we don't own the selection (yet), come up with some reasonable
671         ** defaults
672         */
673         disJoint = True; 
674         oldBegin = begin;
675         oldEnd   = end;        
676     }
677
678
679     selectInfo->begin = begin;
680     selectInfo->end   = end;
681
682     if (begin <= end)
683     {
684         if (selectInfo->ownPrimary == False)
685         {
686             if (!XtOwnSelection((Widget)tw, XA_PRIMARY, selectTime,
687                                 _DtTermPrimSelectConvert,
688                                 _DtTermPrimSelectLoseSelection,
689                                 (XtSelectionDoneProc) NULL))
690             {
691                 /* 
692                 ** XtOwnSelection failed, make a dummy call to setSelection
693                 ** (with begin > end) to clear things up...
694                 */
695                 setSelection(tw, 1, -99, selectTime, False);
696             }
697             else
698             {
699                 selectInfo->ownPrimary  = True;
700                 selectInfo->primaryTime = selectTime;
701             }
702         }
703
704         /* 
705         ** now highlight the currently selected text...
706         */
707         if (selectInfo->ownPrimary)
708         {
709             if (disJoint == True)
710             {
711                 /* 
712                 ** the selections are disjoint, simply draw the new one
713                 */
714                 _DtTermPrimRenderRefreshTextLinear((Widget)tw, begin, end - 1);
715             }
716             else
717             {
718                 if (begin != oldBegin)
719                 {
720                     if (begin < oldBegin)
721                     {
722                         /* 
723                         ** refresh from the new beginning to the old 
724                         ** beginning
725                         */
726                         _DtTermPrimRenderRefreshTextLinear((Widget)tw, begin,
727                                                      oldBegin - 1);
728                     }
729                     else if (oldBegin < begin)
730                     {
731                         /* 
732                         ** refresh from the old beginning to the new 
733                         ** beginning
734                         **
735                         ** NOTE: in this case we want to unhighlight
736                         **       previously selected text, so we
737                         **       temporarily set ownPrimary to false
738                         */
739                         selectInfo->ownPrimary = False;
740                         _DtTermPrimRenderRefreshTextLinear((Widget)tw, oldBegin,
741                                                      begin - 1);
742                         selectInfo->ownPrimary = True;
743                     }
744                 }
745                 if (end != oldEnd)
746                 {
747                     if (end < oldEnd)
748                     {
749                         /* 
750                         ** refresh from the new end to the original end
751                         **
752                         ** NOTE: in this case we want to unhighlight
753                         **       previously selected text, so we
754                         **       temporarily set ownPrimary to false
755                         */
756                         selectInfo->ownPrimary = False;
757                         _DtTermPrimRenderRefreshTextLinear((Widget)tw, end,
758                                                      oldEnd - 1);
759                         selectInfo->ownPrimary = True;
760                     }
761                     else if (oldEnd < end)
762                     {
763                         /* 
764                         ** refresh from the old end to the new end.
765                         */
766                         _DtTermPrimRenderRefreshTextLinear((Widget)tw, oldEnd,
767                                                      end - 1);
768                     }
769                 }
770             }
771         }
772     }
773     else
774     {
775         if (!fromLoseSelection)
776         {
777             XtDisownSelection((Widget)tw, XA_PRIMARY, selectTime);
778         }
779         selectInfo->ownPrimary = False;
780     }
781
782     selectLineBegin = selectInfo->begin / (selectInfo->columns + 1);
783     selectColBegin = selectInfo->begin % (selectInfo->columns + 1);
784     selectLineEnd = (selectInfo->end - 1) / (selectInfo->columns + 1);
785     selectColEnd = (selectInfo->end - 1) % (selectInfo->columns + 1);
786
787     DebugF('c', 1,
788             fprintf(stderr, "set selection units: %d-%d  lines: %d-%d\n",
789             selectInfo->begin, selectInfo->end,
790             selectLineBegin,
791             selectLineEnd));
792     if (tw->term.tpd->useHistoryBuffer && tw->term.tpd->lastUsedHistoryRow>0) {
793         if (selectLineEnd > tw->term.tpd->lastUsedHistoryRow) {
794             (void) _DtTermPrimBufferSetSelectLines(tw->term.tpd->historyBuffer,
795                     selectLineBegin, selectColBegin,
796                     tw->term.tpd->lastUsedHistoryRow - 1, selectInfo->columns);
797         } else {
798             (void) _DtTermPrimBufferSetSelectLines(tw->term.tpd->historyBuffer,
799                     selectLineBegin, selectColBegin,
800                     selectLineEnd, selectColEnd);
801         }
802         selectLineBegin -= tw->term.tpd->lastUsedHistoryRow;
803         if (selectLineBegin < 0) {
804             selectLineBegin = 0;
805             selectColBegin = 0;
806         }
807         selectLineEnd -= tw->term.tpd->lastUsedHistoryRow;
808     }
809     
810     if (selectLineEnd > tw->term.tpd->lastUsedRow) {
811         (void) _DtTermPrimBufferSetSelectLines(tw->term.tpd->termBuffer,
812                 selectLineBegin, selectColBegin,
813                 tw->term.tpd->lastUsedRow, selectInfo->columns);
814     } else {
815         (void) _DtTermPrimBufferSetSelectLines(tw->term.tpd->termBuffer,
816                 selectLineBegin, selectColBegin,
817                 selectLineEnd, selectColEnd);
818     }
819     Debug('c', fprintf(stderr, ">>setSelection() finishing b\n"));
820 }
821
822
823 static void
824 handleSelection
825 (
826     DtTermPrimitiveWidget   tw,
827     int                     x,
828     int                     y,
829     Time                    selectTime
830 )
831 {
832     XmTextPosition   position;
833     XmTextPosition   newBegin;
834     XmTextPosition   newEnd;
835     TermSelectInfo   selectInfo = tw->term.tpd->selectInfo;
836
837     Debug('c', fprintf(stderr, ">>handleSelection() starting\n"));
838
839     position = xyToPos(tw, x, y);
840     newBegin = scan(tw, position, selectInfo->scanType, scanLeft,
841                     1,  False);
842     newEnd   = scan(tw, position, selectInfo->scanType, scanRight,
843                     1,  selectInfo->scanType == XmSELECT_LINE);
844
845     setSelection(tw, newBegin, newEnd, selectTime, False);
846     
847     if ((position - newBegin) <
848         (newEnd - position))
849     {
850         selectInfo->extendDir = scanLeft;
851     }
852     else
853     {
854         selectInfo->extendDir = scanRight;
855     }
856     selectInfo->origBegin = newBegin;
857     selectInfo->origEnd   = newEnd;
858 }
859
860
861 /************************************************************************
862  *                                                                      *
863  * browseScroll - timer proc that scrolls the list if the user has left *
864  *              the window with the button down. If the button has been *
865  *              released, call the standard click stuff.                *
866  *                                                                      *
867  ************************************************************************/
868 /* ARGSUSED */
869 static void
870 browseScroll
871 (
872         XtPointer closure,
873         XtIntervalId *id 
874 )
875 {
876     Widget w = (Widget) closure;
877     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
878     DtTermPrimData          tpd         = tw->term.tpd;
879     TermSelectInfo selectInfo           = tpd->selectInfo ;
880     XmScrollBarWidget vsb = (XmScrollBarWidget) tw->term.verticalScrollBar;
881     unsigned long interval;
882
883     if (selectInfo->cancel) {
884        selectInfo->selectID = 0;
885        return;
886     }
887
888     if (!selectInfo->selectID) return;
889
890     _DtTermPrimScrollComplete(w, True);
891     if ( selectInfo->isScrollUp ) {
892        if ( tpd->lastUsedRow-1 >= tpd->topRow + tw->term.rows) 
893                  _DtTermPrimScrollText(w, 1);
894      }
895     else
896        _DtTermPrimScrollText(w, -1);
897     _DtTermPrimScrollComplete(w, True);
898     if (selectInfo->extending)
899       doExtendedSelection(w, XtLastTimestampProcessed(XtDisplay(w)));
900
901     if (vsb)
902        interval = (unsigned long) vsb->scrollBar.repeat_delay;
903     else
904        interval = 100;
905
906     XSync (XtDisplay(w), False);
907
908     selectInfo->selectID = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
909                                    interval, browseScroll, (XtPointer) w);
910 }
911
912 /* ARGSUSED */
913 static Boolean
914 CheckTimerScrolling
915 (
916     Widget w,
917     XEvent *event 
918 )
919 {
920     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
921     DtTermPrimData          tpd         = tw->term.tpd;
922     TermSelectInfo          selectInfo  = tpd->selectInfo;
923     XmScrollBarWidget vsb = (XmScrollBarWidget) tw->term.verticalScrollBar;
924     unsigned long interval;
925
926     selectInfo->extend.x = event->xmotion.x;
927     selectInfo->extend.y = event->xmotion.y;
928
929     if ( (event->xmotion.y > (int) tpd->offsetY) &&
930         (event->xmotion.y < (int) (tpd->offsetY + tw->term.rows * 
931                                                   tpd->cellHeight))) {
932
933        if (selectInfo->selectID) {
934           XtRemoveTimeOut(selectInfo->selectID);
935           selectInfo->selectID = 0;
936        }
937     } else {
938        /* above the text */
939         if (event->xmotion.y <= (int) tpd->offsetY) {
940            selectInfo->extend.x = 0;
941            selectInfo->extend.y  = (int) (tpd->offsetY);
942            selectInfo->isScrollUp = False ;
943
944        /* below the text */
945         } else if (event->xmotion.y >= (int) (tpd->offsetY + tw->term.rows *
946                                                   tpd->cellHeight)) {
947            selectInfo->extend.x = tw->core.width;
948            selectInfo->extend.y = (int) (tpd->offsetY + tw->term.rows *
949                                                   tpd->cellHeight);
950            selectInfo->isScrollUp = True ;
951         }
952
953        if (vsb)
954           interval = (unsigned long) vsb->scrollBar.initial_delay;
955        else
956           interval = 200;
957
958        if (!selectInfo->selectID)
959          selectInfo->selectID = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
960                                          interval, browseScroll, (XtPointer) w);
961        return True;
962     }
963     return False;
964 }
965
966 /* 
967 ** Create and initialize the selection specific information
968 */
969 TermSelectInfo
970 _DtTermPrimSelectCreate
971 (
972     Widget  w
973 )
974 {
975     DtTermPrimitiveWidget   tw  = (DtTermPrimitiveWidget)w;
976     DtTermPrimData          tpd = tw->term.tpd;
977     TermSelectInfo          selectInfo;
978     int                     i;    
979
980     selectInfo = (TermSelectInfo)XtMalloc(sizeof(TermSelectInfoRec));
981     
982     selectInfo->begin         = 0;
983     selectInfo->end           = 0;
984     selectInfo->columns       = tw->term.columns;
985     selectInfo->rows          = tpd->bufferRows + tpd->historyBufferRows;
986     selectInfo->direction     = (TermScanDirection) XmTEXT_FORWARD;
987     selectInfo->extend.x      = 0;
988     selectInfo->extend.y      = 0;
989     selectInfo->extending     = False;
990     selectInfo->hint.x        = 0;
991     selectInfo->hint.y        = 0;
992     selectInfo->lastTime      = 0;
993     selectInfo->origBegin     = 0;
994     selectInfo->origEnd       = 0;
995     selectInfo->ownPrimary    = False;
996     selectInfo->threshold     = 5;
997     selectInfo->selectID      = 0;
998     selectInfo->selectType    = TermSelect_NORMAL;
999     selectInfo->scanType      = defaultScanArray[0];
1000     selectInfo->scanArraySize = XtNumber(defaultScanArray);
1001     selectInfo->scanArray     = (XmTextScanType *)
1002                                 XtMalloc(selectInfo->scanArraySize * 
1003                                          sizeof(XmTextScanType));
1004     selectInfo->cancel        = True;   /* used by scroll selection */
1005     selectInfo->anchor        = -1;     /* in case extend happens before set*/
1006     selectInfo->sel_start     = False;
1007     for (i = 0; i < selectInfo->scanArraySize; i++)
1008     {
1009         selectInfo->scanArray[i] = defaultScanArray[i];
1010     }
1011     
1012     RegisterDropSite(w);
1013     return(selectInfo);
1014 }
1015
1016 void
1017 _DtTermPrimSelectInitBtnEvents(Widget w) 
1018 {
1019     Boolean btn1_transfer = False;
1020     XtVaGetValues((Widget)XmGetXmDisplay(XtDisplay(w)), "enableBtn1Transfer",
1021            &btn1_transfer, NULL);
1022     if (btn1_transfer)
1023         XtOverrideTranslations(w,
1024             XtParseTranslationTable(_DtTermEventBindingsCDE));
1025     if (btn1_transfer == True) /* for btn2 extend case */
1026         XtOverrideTranslations(w,
1027             XtParseTranslationTable(_DtTermEventBindingsCDEBtn2));
1028 }
1029
1030 void
1031 _DtTermPrimSelectDisown 
1032 (
1033     Widget          w
1034 )
1035 {
1036     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
1037     DtTermPrimData          tpd         = tw->term.tpd;
1038     TermSelectInfo          selectInfo = tpd->selectInfo;
1039
1040     if (selectInfo->ownPrimary == True)
1041     {
1042         XtDisownSelection(w, XA_PRIMARY, getServerTime(w));
1043         selectInfo->ownPrimary = False ;
1044     }
1045 }
1046
1047 void
1048 _DtTermPrimSelectDestroy
1049 (
1050     Widget          w,
1051     TermSelectInfo  selectInfo
1052 )
1053 {
1054     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
1055     DtTermPrimData          tpd         = tw->term.tpd;
1056
1057     if (selectInfo->ownPrimary == True)
1058     {
1059         XtDisownSelection(w, XA_PRIMARY, getServerTime(w));
1060     }
1061     selectInfo->ownPrimary = False ;
1062     XtFree((char *) selectInfo->scanArray);
1063     XtFree((char *) selectInfo);
1064     tpd->selectInfo = NULL ;
1065 }
1066
1067
1068 /* 
1069 ** determine how much (if any) of the text is selected
1070 **
1071 ** NOTE:
1072 **     beginCol + width will never exceed the width of the terminal
1073 **     buffer
1074 */
1075 Boolean
1076 _DtTermPrimSelectIsInSelection
1077 (
1078     Widget      w,
1079     int         row,
1080     short       startCol,
1081     short       width,
1082     short      *selWidth
1083 )
1084 {
1085     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
1086     DtTermPrimData          tpd         = tw->term.tpd;
1087     TermSelectInfo          selectInfo  = tpd->selectInfo;
1088     Boolean                 inSelection = True;
1089     XmTextPosition          endPosition;
1090     XmTextPosition          position;
1091     XmTextPosition          begin;
1092     XmTextPosition          end;
1093     short                   beginRow, beginCol;
1094     short                   endRow  , endCol;
1095
1096     position    = rowColToPos(tw, row, startCol);
1097     endPosition = position + width;
1098
1099     begin = selectInfo->begin;
1100     end   = selectInfo->end;
1101
1102     if ((begin >= endPosition) || (end <= position))
1103     {
1104         /*
1105         ** outside of selection range...
1106         */
1107         inSelection = False;
1108     }
1109     else
1110     {
1111         /* 
1112         ** we're in the selection range, clip endPosition as necessary...
1113         */
1114         if (position < begin)
1115         {
1116             /*
1117             ** we start to the left of the selection...
1118             */
1119             inSelection = False;
1120             endPosition = MIN(endPosition, begin);
1121
1122         } 
1123         else 
1124         {
1125             /*
1126             ** we must be in the selection, clip endPosition as
1127             ** necessary...
1128             */
1129             endPosition = MIN(endPosition, end);
1130
1131         }
1132     }
1133
1134     *selWidth = endPosition - position;
1135     return(inSelection);
1136 }
1137
1138 /*ARGSUSED*/
1139 void
1140 _DtTermPrimSelectDoSelection
1141 (
1142     Widget      w,
1143     XEvent     *event,
1144     String     *params,
1145     Cardinal   *paramCount
1146 )
1147 {
1148     DtTermPrimitiveWidget  tw = (DtTermPrimitiveWidget) w;
1149
1150     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectDoSelection() starting\n"));
1151
1152     handleSelection(tw, event->xbutton.x,  event->xbutton.y,
1153                     event->xbutton.time);
1154 }               
1155
1156 /*ARGSUSED*/
1157 void
1158 _DtTermPrimSelectSetHint
1159 (
1160     Widget      w,
1161     XEvent     *event,
1162     String     *params,
1163     Cardinal   *paramCount
1164 )
1165 {
1166     TermSelectInfo  selectInfo = 
1167                     ((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
1168
1169     selectInfo->hint.x = event->xbutton.x;
1170     selectInfo->hint.y = event->xbutton.y;
1171 }
1172
1173 /*ARGSUSED*/
1174 void
1175 _DtTermPrimSelectStart
1176 (
1177     Widget      w,
1178     XEvent     *event,
1179     String     *params,
1180     Cardinal   *paramCount
1181 )
1182 {
1183     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget)w;
1184     TermSelectInfo          selectInfo = tw->term.tpd->selectInfo;
1185     XButtonEvent           *btnEvent   = (XButtonEvent *) event;
1186     XmTextPosition          begin;
1187     XmTextPosition          end;
1188
1189     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectStart() starting\n"));
1190
1191     /* 
1192     ** set the selection hints, and scan type
1193     */
1194     _DtTermPrimSelectSetHint(w, event, params, paramCount);
1195     setScanType(w, event);
1196
1197     /* 
1198     ** Set the current anchor point
1199     */
1200     selectInfo->anchor = xyToPos(tw, btnEvent->x, btnEvent->y);
1201     
1202     if (selectInfo->scanType != XmSELECT_POSITION ||
1203             _DtTermPrimSelectGetSelection(w, &begin, &end) && begin != end
1204          )
1205     {
1206         _DtTermPrimSelectDoSelection(w, event, params, paramCount);
1207     }
1208 }
1209
1210 /*ARGSUSED*/
1211 void
1212 _DtTermPrimSelectGrabFocus
1213 (
1214     Widget w,
1215     XEvent *event,
1216     String *params,
1217     Cardinal *paramCount
1218 )
1219 {
1220     DtTermPrimitiveWidget   tw       = (DtTermPrimitiveWidget)w;
1221     DtTermPrimData          tpd      = tw->term.tpd;
1222     TermSelectInfo          selectInfo = tpd->selectInfo;
1223     XButtonEvent           *btnEvent = (XButtonEvent *) event;
1224
1225     /* setDebugFlags("c") ; */
1226     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectGrabFocus() starting\n"));
1227     
1228     /* turn off the cursor */
1229     _DtTermPrimCursorOff(w);
1230
1231     selectInfo->cancel = False;
1232     tw->term.allowOsfKeysyms = True;   /* normal dtterm doesn't honor these*/
1233     /* 
1234     ** constrain the button event to the terminal's text area
1235     */
1236     if (btnEvent->x <= (int) tpd->offsetX)
1237     {
1238         /* left */
1239         btnEvent->x = (int)(tpd->offsetX + 1);
1240     } else if (btnEvent->x >= (int)(tw->core.width - tpd->offsetX))
1241     {
1242         /* right */
1243         btnEvent->x = (int)(tw->core.width - tpd->offsetX - 1);
1244     } 
1245
1246     if (btnEvent->y <= (int)tpd->offsetY)
1247     {
1248         /* above */
1249         btnEvent->y = (int)(tpd->offsetY + 1);
1250     }
1251     else if (btnEvent->y - ((int)(tpd->offsetY + 
1252                                   ((tpd->lastUsedRow - tpd->topRow) *
1253                                    tpd->cellHeight))) >= selectInfo->threshold)
1254     {
1255         /* below */
1256         btnEvent->y = (int)(tpd->offsetY + ((tpd->lastUsedRow - tpd->topRow) *
1257                                            tpd->cellHeight) - 1);
1258     }
1259     
1260     if (_XmGetFocusPolicy(w) == XmEXPLICIT)
1261         (void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1262
1263     _DtTermPrimSelectStart(w, event, params, paramCount);
1264 }
1265
1266
1267 static
1268 Boolean
1269 dragged
1270 (
1271     TermSelectionHint   hint,
1272     XEvent             *event,
1273     int                 threshold
1274 )
1275 {
1276     return ((abs(hint.x - event->xbutton.x) > threshold) || 
1277             (abs(hint.y - event->xbutton.y) > threshold));
1278 }
1279
1280 /* ARGSUSED */
1281 static void 
1282 doExtendedSelection
1283 (
1284     Widget  w,
1285     Time    eventTime
1286
1287 {
1288     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget) w;
1289     TermSelectInfo          selectInfo = tw->term.tpd->selectInfo;
1290     XmTextPosition          position;
1291     XmTextPosition          begin;
1292     XmTextPosition          end;
1293     XmTextPosition          cursorPos;
1294     float                   midPoint;
1295
1296     if (selectInfo->cancel) {
1297           if (selectInfo->selectID) XtRemoveTimeOut(selectInfo->selectID);
1298           selectInfo->selectID = 0;
1299           return;
1300        }
1301
1302     position = xyToPos(tw, selectInfo->extend.x, selectInfo->extend.y);
1303
1304     if (!(_DtTermPrimSelectGetSelection(w, &begin, &end)) || 
1305         (begin == end))
1306     {
1307         begin                 = position;
1308         end                   = position;
1309         if ( selectInfo->anchor <0) selectInfo->anchor  = position;   
1310         selectInfo->origBegin = selectInfo->anchor;
1311         selectInfo->origEnd   = selectInfo->anchor;
1312         midPoint              = (float)selectInfo->anchor;
1313     }
1314     else 
1315     {
1316         midPoint = (float)
1317                   (((float)(selectInfo->origEnd - 
1318                              selectInfo->origBegin) / 2.0) +
1319                     (float)selectInfo->origBegin);
1320     }
1321
1322     /*
1323     ** shift anchor and direction to opposite end of the selection
1324     */
1325     if ((float)(position) <= midPoint)
1326     {
1327         selectInfo->anchor = selectInfo->origEnd;
1328         if (!selectInfo->extending)
1329         {
1330              selectInfo->extendDir = scanLeft;
1331         }
1332     } 
1333     else if ((float)(position) > midPoint)
1334     {
1335           selectInfo->anchor = selectInfo->origBegin;
1336           if (!selectInfo->extending)
1337           {
1338              selectInfo->extendDir = scanRight;
1339           }
1340     } 
1341
1342     selectInfo->extending = TRUE;
1343
1344     /*
1345     ** check for change in extend direction
1346     */
1347     if ((selectInfo->extendDir == scanRight && 
1348          position < selectInfo->anchor) ||
1349         (selectInfo->extendDir == scanLeft && 
1350          position > selectInfo->anchor))
1351     {
1352         selectInfo->extendDir = (selectInfo->extendDir == scanRight) ? 
1353                                 scanLeft : scanRight;
1354
1355         begin = selectInfo->begin;
1356         end   = selectInfo->end;
1357     }
1358     
1359     
1360     if (selectInfo->extendDir == scanRight)
1361     {
1362         cursorPos = scan(tw, position, selectInfo->scanType, scanRight, 1,
1363                          selectInfo->scanType == XmSELECT_LINE);
1364         end       = cursorPos;
1365         begin     = selectInfo->anchor;
1366     } 
1367     else
1368     {
1369         cursorPos = scan(tw, position, selectInfo->scanType, scanLeft, 1,
1370                          FALSE);
1371         begin     = cursorPos;
1372         end       = selectInfo->anchor;
1373         if (selectInfo->scanType == XmSELECT_WORD && 
1374                                              (int)tw->term.tpd->cellWidth > 1)
1375         {
1376             if (position == scan (tw, begin, selectInfo->scanType, scanRight, 1,
1377                                   FALSE))
1378             {
1379                 begin = cursorPos = position;
1380             }
1381         }
1382     }
1383
1384     setSelection(tw, begin, end, eventTime, False);
1385 }
1386
1387 void
1388 _DtTermPrimSelectExtendStart(
1389         Widget w,
1390         XEvent *event,
1391         String *params,
1392         Cardinal *num_params )
1393 {
1394     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget)w;
1395     TermSelectInfo          selectInfo = tw->term.tpd->selectInfo;
1396
1397     selectInfo->cancel = False;
1398     tw->term.allowOsfKeysyms = True  ;
1399
1400     _DtTermPrimSelectExtend(w, event, params, num_params);
1401 }
1402
1403 /*ARGSUSED*/
1404 void
1405 _DtTermPrimSelectExtend
1406 (
1407     Widget      w,
1408     XEvent     *event,
1409     String     *params,
1410     Cardinal   *paramCount
1411 )
1412 {
1413     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget)w;
1414     TermSelectInfo          selectInfo = tw->term.tpd->selectInfo;
1415
1416     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectExtend() starting\n"));
1417
1418     /* turn off the cursor */
1419     _DtTermPrimCursorOff(w);
1420
1421     if (_XmGetFocusPolicy(w) == XmEXPLICIT)
1422     (void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1423
1424     if (selectInfo->cancel) return ;  
1425
1426     if ((selectInfo->hint.x > 0) || (selectInfo->hint.y > 0))
1427     {
1428         if (dragged(selectInfo->hint, event, selectInfo->threshold))
1429         {
1430             /*
1431             ** extend the selection
1432             */
1433             handleSelection(tw,selectInfo->hint.x,selectInfo->hint.y, 
1434                                      event->xbutton.time);
1435             selectInfo->hint.x    = 0;
1436             selectInfo->hint.y    = 0;
1437             selectInfo->extending = True;
1438         }
1439         else
1440         {
1441             /* 
1442             ** do nothing
1443             */
1444             return;
1445         }
1446     }
1447     /*
1448     ** check for timer scrolling here
1449     ** NOTE: CheckTimerScrolling(w,event) will set extend.[x|y]
1450     *      selectInfo->extend.x = event->xbutton.x;
1451     *      selectInfo->extend.y = event->xbutton.y;
1452     */
1453     if (!CheckTimerScrolling(w,event) )
1454        doExtendedSelection(w, event->xbutton.time);
1455 }
1456
1457 /*ARGSUSED*/
1458 void
1459 _DtTermPrimSelectExtendEnd
1460 (
1461     Widget w,
1462     XEvent *event,
1463     String *params,
1464     Cardinal *paramCount
1465 )
1466 {
1467     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget)w;
1468     TermSelectInfo          selectInfo = tw->term.tpd->selectInfo;
1469
1470     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectExtendEnd() starting\n"));
1471  
1472     selectInfo->cancel = True;   /* used by scroll selection */
1473     tw->term.allowOsfKeysyms = False;
1474
1475     if (selectInfo->extending)
1476     {
1477         _DtTermPrimSelectGetSelection(w, &selectInfo->origBegin, 
1478                                          &selectInfo->origEnd);
1479         setSelection(tw, selectInfo->origBegin, selectInfo->origEnd, 
1480                                             event->xbutton.time, False);
1481         /* _DtTermPrimSelectExtend(w, event, params, paramCount);*/
1482     }
1483     
1484     if (selectInfo->selectID > 0)
1485     {
1486         XtRemoveTimeOut(selectInfo->selectID);
1487         selectInfo->selectID = 0;
1488     }
1489     
1490     selectInfo->extend.x  = 0;
1491     selectInfo->extend.y  = 0;
1492     selectInfo->extending = False;
1493     selectInfo->hint.x    = 0;
1494     selectInfo->hint.y    = 0;
1495
1496     /* turn off the cursor */
1497     _DtTermPrimCursorOn(w);
1498 }
1499
1500 /*ARGSUSED*/
1501 static void
1502 doHandleTargets
1503 (
1504     Widget          w,
1505     XtPointer       closure,
1506     Atom           *seltype,
1507     Atom           *type,
1508     XtPointer       value,
1509     unsigned long  *length,
1510     int            *format
1511 )
1512 {
1513     _TermSelectPrimaryRec  *primSelect = (_TermSelectPrimaryRec *) closure;
1514     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget)w;
1515     DtTermPrimData          tpd        = tw->term.tpd;
1516     TermSelectInfo          selectInfo = tpd->selectInfo;
1517     XTextProperty           tmpProp;
1518     XmTextBlockRec          block;
1519     int                     i, status;
1520     char                   *pChar;
1521     char                   *pCharEnd;
1522     char                   *pCharFollow;
1523     int                     malloc_size=0 , numVals ;
1524     char                   *total_tmp_value ;
1525     char                  **tmp_value ;
1526
1527     Debug('c', fprintf(stderr, ">>doHandleTargets() starting\n"));
1528
1529     if (_XmGetFocusPolicy(w) == XmEXPLICIT)
1530     {
1531         (void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1532     }
1533     
1534     if (*type == XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False) ||
1535         *type == XA_STRING)
1536     {
1537
1538         tmpProp.value    = (unsigned char *) value;
1539         tmpProp.encoding = *type;
1540         tmpProp.format   = *format;
1541         tmpProp.nitems   = *length;
1542         numVals           = 0;
1543         status            = XmbTextPropertyToTextList(XtDisplay(w), &tmpProp,
1544                                                       &tmp_value, &numVals );
1545
1546         /*
1547         ** if no conversions, numVals  doesn't change
1548         */
1549         if (numVals  && (status == Success || status > 0))
1550         { 
1551             for (i = 0; i < numVals  ; i++)
1552             {
1553                  malloc_size += strlen(tmp_value[i]);
1554             }
1555             total_tmp_value = XtMalloc ((unsigned) malloc_size + 1);
1556             total_tmp_value[0] = '\0';
1557             for (i = 0; i < numVals  ; i++)
1558             {
1559                 strcat(total_tmp_value, tmp_value[i]);
1560             }
1561             block.ptr    = total_tmp_value;
1562             block.length = strlen(total_tmp_value);
1563             block.format = XmFMT_8_BIT;
1564             XFreeStringList(tmp_value);
1565         } 
1566         else
1567         {
1568             malloc_size      = 1; /* to force space to be freed */
1569             total_tmp_value  = XtMalloc ((unsigned)1);
1570             *total_tmp_value = '\0';
1571             block.ptr = total_tmp_value;
1572             block.length = 0;
1573             block.format = XmFMT_8_BIT;
1574         }
1575      } else {
1576     
1577         block.ptr    = (char*)value;
1578         block.length = (int) *length; /* NOTE: this causes a truncation on
1579                            some architectures */
1580         block.format = XmFMT_8_BIT;
1581      }
1582  
1583      pCharEnd    = block.ptr + block.length;
1584      pCharFollow = (char *)block.ptr;
1585
1586      for (pChar = (char *)block.ptr; pChar < pCharEnd; pChar++)
1587      {
1588          if (*pChar == '\n')
1589          {
1590              *pChar = '\r';
1591              DtTermSubprocSend(w, (unsigned char *) pCharFollow,
1592                            pChar - pCharFollow + 1);
1593              pCharFollow = pChar + 1;
1594          }        
1595      }
1596      if (pCharFollow < pCharEnd)
1597      {
1598          DtTermSubprocSend(w, (unsigned char *) pCharFollow,
1599                        pCharEnd - pCharFollow);
1600      }
1601
1602     if (malloc_size != 0) XtFree(total_tmp_value);
1603     XtFree((char *)value);
1604     if (primSelect && (--primSelect->ref_count == 0))
1605     {
1606        XtFree((char *)primSelect);
1607     }    
1608     value = NULL ;
1609 }
1610
1611 /*
1612 ** Look at the target list and determine what target to place in the
1613 ** pair.  it will then do any necessary conversions before "thrusting"
1614 ** the selection value onto the receiver.  this will guarantee the
1615 ** best chance at a successful exchange.
1616 */
1617 /*ARGSUSED*/
1618 static void
1619 handleTargets
1620 (
1621     Widget          w,
1622     XtPointer       closure,
1623     Atom           *selType,
1624     Atom           *type,
1625     XtPointer       value,
1626     unsigned long  *length,
1627     int            *format
1628 )
1629 {
1630     Atom                    CS_OF_LOCALE;
1631     Atom                    COMPOUND_TEXT;
1632     Boolean                 supportsLocaleData;
1633     Boolean                 supportsCompoundText;
1634     Atom                   *atomPtr;
1635     _TermSelectRec         *tmpAction;
1636     _TermSelectPrimaryRec  *primSelect; 
1637     char                   *abcString;
1638     XTextProperty           tmpProp;
1639     int                     status;
1640     XtPointer               closures[2];
1641     Atom                    targets[2];
1642     int                     i;
1643
1644     /* 
1645     ** make sure we have something to do...
1646     */
1647     tmpAction = (_TermSelectRec *) closure;
1648     if (!length || *length == 0) {
1649        XtFree((char *)value);
1650        value = NULL;
1651        XtFree((char *)tmpAction->event);
1652        XtFree((char *)tmpAction);
1653        return;
1654     }
1655
1656     COMPOUND_TEXT        = XmInternAtom(XtDisplay(w),"COMPOUND_TEXT", False);
1657     supportsLocaleData   = False;
1658     supportsCompoundText = False;
1659     abcString            = "ABC";  /* characters in XPCS, so... safe */
1660     atomPtr              = (Atom *)value;
1661
1662     tmpProp.value = NULL;
1663     status = XmbTextListToTextProperty(XtDisplay(w), &abcString, 1,
1664                                       (XICCEncodingStyle)XTextStyle, &tmpProp);
1665     if (status == Success)
1666     {
1667         CS_OF_LOCALE = tmpProp.encoding;
1668     }
1669     else
1670     {
1671         /* 
1672         ** Kludge for failure of XmbText... to 
1673         ** handle XPCS characters.  Should never 
1674         ** happen, but this prevents a core dump 
1675         ** if X11 is broken.
1676         */
1677         CS_OF_LOCALE = (Atom)9999;
1678     }
1679     if (tmpProp.value != NULL) 
1680     {
1681         XFree((char *)tmpProp.value);
1682     }
1683
1684     for (i = 0; i < *length; i++, atomPtr++)
1685     {
1686         if (*atomPtr == CS_OF_LOCALE)
1687         {
1688             supportsLocaleData = True;
1689             break;
1690         }
1691         if (*atomPtr == COMPOUND_TEXT)
1692         {
1693             supportsCompoundText = True;
1694         }
1695     }
1696     primSelect = (_TermSelectPrimaryRec *)
1697                  XtMalloc((unsigned) sizeof(_TermSelectPrimaryRec));
1698
1699     /*
1700     ** If owner and I are using the same codeset, ask for it.  If not,
1701     ** and if the owner supports compound text, ask for compound text.
1702     ** If not, fall back position is to ask for STRING and try to
1703     ** convert it locally.
1704     */
1705     if (supportsLocaleData)
1706     {
1707         primSelect->target = targets[0] = CS_OF_LOCALE;
1708     }
1709     else if (supportsCompoundText)
1710     {
1711         primSelect->target = targets[0] = COMPOUND_TEXT;
1712     }
1713     else
1714     {
1715         primSelect->target = targets[0] = XA_STRING;
1716     }
1717     closures[0] = (char *)primSelect;
1718
1719     primSelect->ref_count = 1;
1720     /*
1721     ** Make request to call doHandleTargets() with the primary selection.
1722     */
1723     XtGetSelectionValue(w, XA_PRIMARY, targets[0], doHandleTargets,
1724                         (XtPointer)primSelect,
1725                         tmpAction->event->xbutton.time);
1726
1727     XtFree((char *)value);
1728     value = NULL;
1729     XtFree((char *)tmpAction->event);
1730     XtFree((char *)tmpAction);
1731 }
1732
1733 static  char *
1734 getString
1735 (
1736     Widget          w,
1737     XmTextPosition  begin,
1738     XmTextPosition  end,
1739     Boolean         needWideChar
1740 )
1741 {
1742     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget) w;
1743     DtTermPrimData          tpd        = tw->term.tpd;
1744     TermSelectInfo          selectInfo = tpd->selectInfo;
1745     TermBuffer              tb;
1746     short                   beginRow, 
1747                             beginCol;
1748     short                   endRow,
1749                             endCol;
1750     short                   thisRow;
1751     short                   numRows;
1752     char                   *buffer;
1753     char                   *pBuf;
1754     short                   len;
1755     
1756     beginRow = begin / (selectInfo->columns + 1);
1757     beginCol = begin - (beginRow * (selectInfo->columns + 1));
1758     endRow   = end / (selectInfo->columns + 1);
1759     endCol   = end - (endRow * (selectInfo->columns + 1));
1760     numRows  = endRow - beginRow + 1;
1761
1762     /*
1763     ** we need to store end - begin characters, a terminating byte, plus
1764     ** a new line for each line...
1765     **
1766     ** NOTE: end - begin could result in a truncated long.
1767     */
1768     buffer = XtMalloc(((int)(end - begin) + 1 + numRows) * sizeof(char)
1769                                       * BYTES_PER_CHAR(tpd->termBuffer));
1770
1771     /* 
1772     ** return a null string if there is nothing to do
1773     */
1774     if (begin == end)
1775     {
1776         *buffer = 0x00;
1777         return(buffer);
1778     }
1779
1780     /* 
1781     ** Accomodate the history buffer as necessary
1782     */
1783     if (tpd->useHistoryBuffer)
1784     {
1785         beginRow -= tpd->lastUsedHistoryRow;
1786         endRow   -= tpd->lastUsedHistoryRow;
1787     }
1788
1789     /*
1790     ** get the first (and possibly only) line of text
1791     */
1792     pBuf = buffer;
1793     if (beginRow == endRow)
1794     {
1795         if (beginRow < 0)
1796         {
1797             tb      = tpd->historyBuffer;
1798             thisRow = beginRow + tpd->lastUsedHistoryRow;
1799         }
1800         else
1801         {
1802             tb      = tpd->termBuffer;
1803             thisRow = beginRow;
1804         }
1805         len = _DtTermPrimBufferGetText(tb, thisRow, beginCol, 
1806                                        endCol - beginCol, pBuf, needWideChar);
1807         pBuf += len;
1808     }
1809     else
1810     {
1811         if (beginRow < 0)
1812         {
1813             tb      = tpd->historyBuffer;
1814             thisRow = beginRow + tpd->lastUsedHistoryRow;
1815         }
1816         else
1817         {
1818             tb      = tpd->termBuffer;
1819             thisRow = beginRow;
1820         }
1821         len = _DtTermPrimBufferGetText(tb, thisRow, beginCol, 
1822                                  selectInfo->columns - beginCol, pBuf,
1823                                  needWideChar);
1824         pBuf += len;
1825         
1826         if ( !_DtTermPrimBufferTestLineWrapFlag(tb,thisRow) ) { 
1827            *pBuf = '\n'; /* newline */
1828            pBuf++;
1829          }
1830
1831         /* 
1832         ** get the middle block (if there is one)
1833         */
1834         beginRow++;
1835         while(beginRow < endRow)
1836         {
1837             if (beginRow < 0)
1838             {
1839                 tb      = tpd->historyBuffer;
1840                 thisRow = beginRow + tpd->lastUsedHistoryRow;
1841             }
1842             else
1843             {
1844                 tb      = tpd->termBuffer;
1845                 thisRow = beginRow;
1846             }
1847             len = _DtTermPrimBufferGetText(tb, thisRow, 0,
1848                                            selectInfo->columns , pBuf,
1849                                            needWideChar);
1850
1851             pBuf += len;
1852             /* if (len != 0 &&  len < selectInfo->columns ) { */
1853             if ( !_DtTermPrimBufferTestLineWrapFlag(tb,thisRow) ) { 
1854                *pBuf = '\n'; /* newline */
1855                pBuf++;
1856              }
1857             beginRow++;
1858         }
1859
1860         /* 
1861         ** get the last line 
1862         */
1863         if (endRow < 0)
1864         {
1865             tb      = tpd->historyBuffer;
1866             thisRow = endRow + tpd->lastUsedHistoryRow;
1867         }
1868         else
1869         {
1870             tb      = tpd->termBuffer;
1871             thisRow = endRow;
1872         }
1873         len = _DtTermPrimBufferGetText(tb, thisRow, 0, endCol, pBuf, 
1874                                        needWideChar);
1875         pBuf += len;
1876     }    
1877     *pBuf = 0x00;
1878
1879     return(buffer);
1880 }
1881
1882 /* 
1883 ** Request targets from selection owner.
1884 */
1885 static void
1886 getTargets
1887 (
1888     Widget      w,
1889     XEvent     *event,
1890     String     *params,
1891     Cardinal   *paramCount
1892 )
1893 {
1894     _TermSelectRec *tmp;
1895     
1896     tmp = (_TermSelectRec*)XtMalloc(sizeof(_TermSelectRec));
1897
1898     /*
1899     ** Request targets from the selection owner so you can decide what to
1900     ** request.  The decision process and request for the selection is
1901     ** taken care of in handleTargets().
1902     */
1903
1904     tmp->event = (XEvent *) XtMalloc(sizeof(XEvent));
1905     memcpy((void *)tmp->event, (void *)event, sizeof(XEvent));
1906
1907     tmp->params     = params;
1908     tmp->num_params = paramCount;
1909
1910     XtGetSelectionValue(w, XA_PRIMARY,
1911                         XmInternAtom(XtDisplay(w), "TARGETS", False),
1912                         handleTargets, (XtPointer)tmp, event->xbutton.time);
1913 }
1914
1915 Boolean
1916 _DtTermPrimSelectConvert
1917 (
1918     Widget          w,
1919     Atom           *selection,
1920     Atom           *target,
1921     Atom           *type,
1922     XtPointer      *value,
1923     unsigned long  *length,
1924     int            *format
1925 )
1926 {
1927     Atom  TARGETS        = XmInternAtom(XtDisplay(w), "TARGETS",         False);
1928     Atom  CS_OF_LOCALE;
1929     Atom  COMPOUND_TEXT  = XmInternAtom(XtDisplay(w), "COMPOUND_TEXT",   False);
1930     Atom  TEXT          = XmInternAtom(XtDisplay(w), "TEXT",            False);
1931     Atom MOTIF_DROP = XmInternAtom(XtDisplay(w), "_MOTIF_DROP", False);
1932     int     maxTargets  = 10;
1933     int     targetCount;
1934     int     status;
1935     Widget widget;
1936     Boolean ownPrimary;
1937     XmTextPosition begin;
1938     XmTextPosition end;
1939     char           *tmpValue;
1940     char           *tmpString = "ABC";  /* characters in XPCS, so... safe */
1941     XTextProperty   tmpProp;
1942     XtPointer c_ptr;
1943     Arg args[1];
1944     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectConvert() starting\n"));
1945
1946     if (*selection == MOTIF_DROP) {
1947        XtSetArg(args[0], XmNclientData, &c_ptr);
1948        XtGetValues(w, args, 1);
1949        widget = (Widget)c_ptr;
1950     } else
1951        widget = w;
1952
1953     if (widget == NULL) return False;
1954
1955     tmpProp.value = NULL;
1956     status = XmbTextListToTextProperty(XtDisplay(widget), &tmpString, 1,
1957                                 (XICCEncodingStyle)XTextStyle, &tmpProp);
1958     if (status == Success)
1959     {
1960         CS_OF_LOCALE = tmpProp.encoding;
1961     }
1962     else
1963     {
1964         /*
1965         ** XmbTextList... SHOULD never fail for
1966         ** XPCS character.  But if it does, this
1967         ** prevents a core dump.
1968         */
1969         CS_OF_LOCALE = (Atom) 9999;
1970     }
1971
1972     if (tmpProp.value != NULL)
1973         XFree((char *) tmpProp.value);
1974
1975
1976     if (*selection == XA_PRIMARY || *selection == MOTIF_DROP)
1977     {
1978         ownPrimary = _DtTermPrimSelectGetSelection(widget, &begin, &end);
1979     }
1980     else
1981     {
1982         return(False);
1983     }
1984
1985     if (*target == TARGETS)
1986     {
1987         Atom *targets = (Atom *)XtMalloc((unsigned)(maxTargets * sizeof(Atom)));
1988
1989         /* 
1990         ** Xt should take care of TIME_STAMP for us.
1991         */
1992         targetCount = 0;    
1993         *value     = (XtPointer)targets;
1994         *targets++ = TARGETS;           targetCount++;
1995         if (!isDebugFSet('s', 1)) {
1996             *targets++ = COMPOUND_TEXT;     targetCount++;
1997         }
1998         if (!isDebugFSet('s', 2)) {
1999             *targets++ = CS_OF_LOCALE;      targetCount++;
2000         }
2001         if (!isDebugFSet('s', 3)) {
2002             *targets++ = TEXT;              targetCount++;
2003         }
2004         if (!isDebugFSet('s', 4)) {
2005             *targets++ = XA_STRING;         targetCount++;
2006         }
2007         *type   = XA_ATOM;
2008         *length = (targetCount * sizeof(Atom)) >> 2; /* convert to work count */
2009         *format = 32;
2010     }
2011     else if (!ownPrimary)
2012     {
2013        return(False);
2014     }  
2015     else if ((*target == XA_STRING && !isDebugFSet('s', 4)) || 
2016              (*target == COMPOUND_TEXT && !isDebugFSet('s', 1)))
2017     {
2018       tmpValue  = getString(widget, begin, end, False);
2019       tmpProp.value = NULL;
2020         if ((*target == XA_STRING) && !isDebugFSet('s', 4)) {
2021             *type     = (Atom) XA_STRING;
2022             *format   = 8;
2023             status  = XmbTextListToTextProperty(XtDisplay(widget), &tmpValue, 1,
2024                                           (XICCEncodingStyle)XStringStyle, 
2025                                           &tmpProp);
2026         }
2027         else if ((*target == COMPOUND_TEXT) && !isDebugFSet('s',1)) {
2028             *type    = COMPOUND_TEXT;
2029             *format  = 8;
2030             status  = XmbTextListToTextProperty(XtDisplay(widget), &tmpValue, 1,
2031                                           (XICCEncodingStyle)XCompoundTextStyle,
2032                                           &tmpProp);
2033         }
2034         XtFree(tmpValue);
2035         if (status == Success || status > 0)
2036         {
2037             /*
2038             ** NOTE: casting tmpProp.nitems could result in a truncated long.
2039             */
2040             if (tmpProp.nitems > 0)
2041               *value  = (XtPointer) XtMalloc((unsigned)tmpProp.nitems);
2042             else
2043               *value  = (XtPointer) XtMalloc(1);
2044
2045             *length = tmpProp.nitems;
2046             memcpy((void*)*value, (void*)tmpProp.value,
2047                    (unsigned)tmpProp.nitems);
2048             if (tmpProp.value != NULL)
2049                 XFree((char*)tmpProp.value);
2050         }
2051         else
2052         {
2053             *value  = NULL;
2054             *length = 0;
2055             if (tmpProp.value != NULL)
2056                 XFree((char*)tmpProp.value);
2057             return(False);
2058         }
2059     }
2060     else if ((*target == CS_OF_LOCALE) && !isDebugFSet('s', 2) ||
2061              (*target == TEXT  && !isDebugFSet('s', 3)))
2062     {
2063         *type   = CS_OF_LOCALE;
2064         *format = 8;
2065         *value  = (XtPointer)getString(widget, begin, end, False);
2066         *length = strlen((char*) *value);
2067     } 
2068    else
2069    {
2070       *value  =  NULL;
2071       *length = 0;
2072       return(False);
2073    }
2074     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectConvert() exiting\n"));
2075     return(True);
2076 }
2077
2078 void
2079 _DtTermPrimSelectLoseSelection
2080 (
2081     Widget  w,
2082     Atom   *selection
2083 )
2084 {
2085     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget)w;
2086     TermSelectInfo          selectInfo = tw->term.tpd->selectInfo;
2087     Boolean                 restoreCursor = False;
2088
2089     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectLoseSelection() starting\n"));
2090
2091     if (*selection == XA_PRIMARY && selectInfo->ownPrimary)
2092     {
2093
2094         /* 
2095         ** We've lost the primary selection, make a  dummy call to 
2096         ** setSelection (with begin > end) to clear things up...
2097         */
2098         /* turn off the cursor */
2099         if (tw->term.tpd->cursorState != CURSORoff) {
2100             _DtTermPrimCursorOff(w);
2101             restoreCursor = True;
2102         }
2103
2104         setSelection(tw, 1, -99, XtLastTimestampProcessed(XtDisplay(w)), True);
2105
2106         /* turn on the cursor */
2107         if (restoreCursor) {
2108             _DtTermPrimCursorOn(w);
2109         }
2110     }
2111     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectLoseSelection() exiting\n"));
2112 }
2113 /*ARGSUSED*/
2114 void
2115 _DtTermPrimSelectBDragRelease
2116 (
2117     Widget w,
2118     XEvent *event,
2119     String *params,
2120     Cardinal *paramCount
2121 )
2122 {
2123     TermSelectInfo  selectInfo = 
2124                     ((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
2125     XButtonEvent    *btnEvent = (XButtonEvent *) event;
2126
2127     Debug('c', fprintf(stderr, ">>_DtTermPrimSelectBDragRelease() starting\n"));
2128
2129     /* Work around for intrinsic bug.  Remove once bug is fixed.
2130     ** this is for drag/drop
2131     */
2132     XtUngrabPointer(w, btnEvent->time);
2133
2134     if ( selectInfo->sel_start ) getTargets(w, event, params, paramCount);
2135 }
2136
2137 /*ARGSUSED*/
2138 void
2139 _DtTermPrimSelectInsert
2140 (
2141     Widget w,
2142     XEvent *event,
2143     String *params,
2144     Cardinal *paramCount
2145 )
2146 {
2147     DtTermPrimitiveWidget   tw         = (DtTermPrimitiveWidget)w;
2148     TermSelectInfo          selectInfo = tw->term.tpd->selectInfo;
2149
2150     if (!selectInfo->cancel)
2151         _DtTermPrimSelectBDragRelease(w, event, params, paramCount);
2152
2153     selectInfo->cancel = True  ;
2154
2155     /* turn on the cursor */
2156     _DtTermPrimCursorOn(w);
2157 }
2158
2159 Boolean
2160 _DtTermPrimSelectIsAboveSelection
2161 (
2162    Widget w,
2163    short row,
2164    short col
2165 )
2166 {
2167     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
2168     DtTermPrimData          tpd         = tw->term.tpd;
2169     TermSelectInfo          selectInfo  = tpd->selectInfo;
2170     XmTextPosition          curPos, endPos;
2171    
2172     endPos = selectInfo->end ;
2173     curPos = rowColToPos(tw,row,col)  ;
2174
2175     if ( curPos < endPos ) 
2176       return(True) ;
2177     else
2178       return(False) ;
2179 }
2180
2181 void
2182 _DtTermPrimSelectResize
2183 (
2184    Widget w
2185 )
2186 {
2187     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
2188     DtTermPrimData          tpd         = tw->term.tpd;
2189     TermSelectInfo          selectInfo  = tpd->selectInfo;
2190     
2191     _DtTermPrimSelectDisown(w) ;
2192     selectInfo->columns  = tw->term.columns ;
2193 }
2194
2195 extern void
2196 _DtTermPrimSelectMoveLines
2197 (
2198    Widget w,
2199    short src,
2200    short dest,
2201    short len
2202 )
2203 {
2204     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
2205     TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
2206     short selectLineBegin;
2207     short selectLineEnd;
2208     TermBuffer pb;
2209     short row,col;
2210
2211     posToBufferRowCol (tw, selectInfo->begin, &pb, &row, &col);
2212
2213     /* if there are no lines, etc.  return... */
2214     if ((len <= 0) || (src == dest) || !selectInfo->ownPrimary ||
2215           pb == tw->term.tpd->historyBuffer )  {
2216         return;
2217     }
2218     if (row >= src && row < (src + len)) {
2219         selectInfo->begin -= (src - dest) * (selectInfo->columns + 1);
2220         selectInfo->end -= (src - dest) * (selectInfo->columns + 1);
2221     } 
2222 }
2223
2224 extern void
2225 _DtTermPrimSelectDeleteLines
2226 (
2227     Widget w,
2228     short src,
2229     short len
2230 )
2231 {
2232     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
2233     TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
2234     short selectLineBegin;
2235     short selectLineEnd;
2236     TermBuffer pb;
2237     short row,col;
2238
2239     posToBufferRowCol (tw, selectInfo->begin, &pb, &row, &col);
2240
2241     /* if there are no lines, etc. return... */
2242     if ((len <= 0) || !selectInfo->ownPrimary ||  
2243             ((tw->term.tpd->scrollLockTopRow > 0 ||
2244               tw->term.tpd->scrollLockBottomRow < tw->term.rows-1)) &&  
2245               row < tw->term.tpd->scrollLockTopRow) {
2246               
2247         return;
2248     }
2249
2250     /* figure out what the begin and end lines are... */
2251     selectLineBegin = selectInfo->begin / (selectInfo->columns + 1);
2252     selectLineEnd = (selectInfo->end - 1) / (selectInfo->columns + 1);
2253
2254     /* if the beginning of the selection is after the source, we need to
2255      * move the selection up...
2256      */
2257     if (selectLineBegin > src) {
2258         selectInfo->begin -= len * (selectInfo->columns + 1);
2259         selectInfo->end -= len * (selectInfo->columns + 1);
2260         if (selectInfo->begin < 0) {
2261             (void) _DtTermPrimSelectDisown(w);
2262         }
2263     }
2264 }
2265
2266 extern void
2267 _DtTermPrimSelectInsertLines
2268 (
2269    Widget w,
2270    short src,
2271    short len
2272 )
2273 {
2274     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
2275     TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
2276     short selectLineBegin;
2277     short selectLineEnd;
2278
2279     /* if there are no lines, return... */
2280     if ((len <= 0) || !selectInfo->ownPrimary)  {
2281         return;
2282     }
2283
2284     /* figure out what the begin and end lines are... */
2285     selectLineBegin = selectInfo->begin / (selectInfo->columns + 1);
2286     selectLineEnd = (selectInfo->end - 1) / (selectInfo->columns + 1);
2287
2288     /* if the beginning of the selection is at or after the source, we need to
2289      * move the selection up...
2290      */
2291     if (selectLineBegin >= src) {
2292         selectInfo->begin += len * (selectInfo->columns + 1);
2293         selectInfo->end += len * (selectInfo->columns + 1);
2294     }
2295 }
2296
2297 void
2298 _DtTermPrimSelectAll
2299 (
2300     Widget w,
2301     XEvent *event,
2302     String *params,
2303     Cardinal *paramCount
2304 )
2305 {
2306     DtTermPrimitiveWidget   tw       = (DtTermPrimitiveWidget)w;
2307     DtTermPrimData          tpd      = tw->term.tpd;
2308     TermSelectInfo          selectInfo = tpd->selectInfo;
2309     XButtonEvent           *btnEvent = (XButtonEvent *) event;
2310     XmTextPosition          begin;
2311     XmTextPosition          end;
2312     
2313     /*  position not used in XmSELECT_ALL case */
2314     begin = scan(tw, (XmTextPosition) 0, XmSELECT_ALL, scanLeft,
2315                     1,  False);
2316     end   = scan(tw, (XmTextPosition) 0, XmSELECT_ALL, scanRight,
2317                     1,  selectInfo->scanType == XmSELECT_LINE);
2318
2319     /* turn off the cursor */
2320     _DtTermPrimCursorOff(w);
2321
2322     setSelection(tw, begin, end, event->xbutton.time, False);
2323
2324     /* turn on the cursor */
2325     _DtTermPrimCursorOn(w);
2326 }
2327
2328 void
2329 _DtTermPrimSelectPage
2330 (
2331     Widget w,
2332     XEvent *event,
2333     String *params,
2334     Cardinal *paramCount
2335 )
2336 {
2337     DtTermPrimitiveWidget   tw       = (DtTermPrimitiveWidget)w;
2338     DtTermPrimData          tpd      = tw->term.tpd;
2339     TermSelectInfo          selectInfo = tpd->selectInfo;
2340     XButtonEvent           *btnEvent = (XButtonEvent *) event;
2341     XmTextPosition begin, end;
2342     short lastRow, width;
2343     TermBuffer pb;
2344
2345     begin = xyToPos(tw, 1, 1);
2346     end   = xyToPos(tw, tw->core.width-1, tw->core.height-1);
2347
2348     /* turn off the cursor */
2349     _DtTermPrimCursorOff(w);
2350
2351     setSelection(tw, begin, end, event->xbutton.time, False);
2352
2353     /* turn on the cursor */
2354     _DtTermPrimCursorOn(w);
2355 }
2356   
2357 /*
2358  * DROP SITE code
2359  */
2360
2361 static XContext _DtTermDNDContext = 0;
2362
2363 static void
2364 DropTransferCallback(
2365         Widget w,
2366         XtPointer closure,
2367         Atom *seltype,
2368         Atom *type,
2369         XtPointer value,
2370         unsigned long *length,
2371         int *format )
2372 {
2373     _DtTermDropTransferRec *transfer_rec = (_DtTermDropTransferRec *) closure;
2374     DtTermPrimitiveWidget   tw   = (DtTermPrimitiveWidget)transfer_rec->widget;
2375     DtTermPrimData          tpd         = tw->term.tpd;
2376     TermSelectInfo          selectInfo  = tpd->selectInfo;
2377
2378      /* When type = NULL, we are assuming a DELETE request has been requested */
2379     if (*type == 0) {
2380       if (value) {
2381            XtFree((char *)value);
2382            value = NULL;
2383         }
2384       return;
2385      }
2386     doHandleTargets((Widget)tw,NULL,seltype,type,value,length,format) ;
2387     if (transfer_rec->move) {
2388        XmDropTransferEntryRec transferEntries[1];
2389        XmDropTransferEntryRec *transferList = NULL;
2390
2391        transferEntries[0].client_data = (XtPointer) transfer_rec;
2392        transferEntries[0].target = XmInternAtom(XtDisplay(w),"DELETE",
2393                                                 False);
2394        transferList = transferEntries;
2395        XmDropTransferAdd(w, transferEntries, 1);
2396     }
2397 }
2398
2399 static void
2400 DeleteDropContext(
2401         Widget w )
2402 {
2403    Display *display = XtDisplay(w); 
2404    Screen  *screen = XtScreen(w);
2405
2406    XDeleteContext(display, (Window)screen, _DtTermDNDContext);
2407 }
2408
2409 static void
2410 SetDropContext(
2411         Widget w )
2412 {
2413    Display *display = XtDisplay(w);
2414    Screen  *screen = XtScreen(w);
2415
2416    _DtTermProcessLock();
2417    if (_DtTermDNDContext == 0)
2418       _DtTermDNDContext = XUniqueContext();
2419    _DtTermProcessUnlock();
2420
2421    XSaveContext(display, (Window)screen,
2422                 _DtTermDNDContext, (XPointer)w);
2423 }
2424
2425 typedef struct _dropDestroyCBClientData { 
2426    _DtTermDropTransferRec *transfer_rec; 
2427    XtCallbackRec *dropDestroyCB; } 
2428 dropDestroyCBClientData;
2429
2430 /* ARGSUSED */
2431 static void
2432 DropDestroyCB(
2433     Widget      w,
2434     XtPointer   clientData,
2435     XtPointer   callData )
2436 {
2437     dropDestroyCBClientData *ptr = (dropDestroyCBClientData *) clientData;
2438
2439     DeleteDropContext(w);
2440
2441     if (ptr) {
2442       if (ptr->transfer_rec)  XtFree((char *) ptr->transfer_rec);
2443       if (ptr->dropDestroyCB)  XtFree((char *) ptr->dropDestroyCB);
2444       XtFree((char *) ptr);
2445     }
2446 }
2447
2448 static void
2449 HandleDrop( Widget w, XmDropProcCallbackStruct *cb )
2450 {
2451     Widget drag_cont, initiator;
2452     /* XmTextWidget tw = (XmTextWidget) w;  */
2453     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
2454     DtTermPrimData          tpd         = tw->term.tpd;
2455     TermSelectInfo          selectInfo  = tpd->selectInfo;
2456     Cardinal numExportTargets, n;
2457     Atom *exportTargets;
2458     Arg args[10];
2459     XmTextPosition insert_pos, left, right;
2460     XtCallbackRec *dropDestroyCB, *dd_cb;
2461     dropDestroyCBClientData *clientData;
2462
2463     clientData = (dropDestroyCBClientData *) XtMalloc(sizeof(dropDestroyCBClientData));
2464     dropDestroyCB = dd_cb = (XtCallbackRec *) XtMalloc(2 * sizeof (XtCallbackRec));
2465
2466     clientData->dropDestroyCB = dropDestroyCB;
2467     dd_cb->callback = DropDestroyCB;
2468     dd_cb->closure = NULL;
2469     dd_cb++;
2470     dd_cb->callback = (XtCallbackProc) NULL;
2471     dd_cb->closure = NULL;    
2472
2473     drag_cont = cb->dragContext;
2474
2475     n = 0;
2476     XtSetArg(args[n], XmNsourceWidget, &initiator); n++;
2477     XtSetArg(args[n], XmNexportTargets, &exportTargets); n++;
2478     XtSetArg(args[n], XmNnumExportTargets, &numExportTargets); n++;
2479     XtGetValues((Widget) drag_cont, args, n);
2480
2481      {
2482        XmDropTransferEntryRec transferEntries[2];
2483        XmDropTransferEntryRec *transferList = NULL;
2484        Atom TEXT = XmInternAtom(XtDisplay(w), "TEXT", False);
2485        Atom COMPOUND_TEXT = XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False);
2486        Atom CS_OF_LOCALE;
2487        char * tmp_string = "ABC"; /* these are characters in XPCS, so... safe */
2488        XTextProperty tmp_prop;
2489        _DtTermDropTransferRec *transfer_rec; 
2490        Cardinal numTransfers = 0;
2491        Boolean locale_found = False;
2492        Boolean c_text_found = False;
2493        Boolean string_found = False;
2494        Boolean text_found = False;
2495        int status;
2496
2497        tmp_prop.value = NULL;
2498
2499        status = XmbTextListToTextProperty(XtDisplay(w), &tmp_string, 1,
2500                                       (XICCEncodingStyle)XTextStyle, &tmp_prop);
2501        if (status == Success)
2502           CS_OF_LOCALE = tmp_prop.encoding;
2503        else
2504           CS_OF_LOCALE = 99999; /* XmbTextList... should never fail for XPCS
2505                                  * characters.  But just in case someones
2506                                  * Xlib is broken, this prevents a core dump.
2507                                  */
2508
2509        if (tmp_prop.value != NULL) XFree((char *)tmp_prop.value);
2510
2511       /* intialize data to send to drop transfer callback  */
2512        transfer_rec = (_DtTermDropTransferRec *)
2513                        XtMalloc(sizeof(_DtTermDropTransferRec));
2514        clientData->transfer_rec = transfer_rec;
2515        transfer_rec->widget = w;
2516      /*  don't actually need all of this for dtterm - it was from Text widget
2517       *transfer_rec->insert_pos = insert_pos;
2518       *transfer_rec->num_chars = 0;
2519       *transfer_rec->timestamp = cb->timeStamp;
2520       *
2521       */
2522
2523       if (cb->operation & XmDROP_MOVE) {
2524          transfer_rec->move = True;
2525       } else {
2526          transfer_rec->move = False;
2527       }
2528
2529        transferEntries[0].client_data = (XtPointer) transfer_rec; 
2530        transferList = transferEntries;
2531        numTransfers = 1;
2532
2533        for (n = 0; n < numExportTargets; n++) {
2534          if (exportTargets[n] == CS_OF_LOCALE) {
2535             transferEntries[0].target = CS_OF_LOCALE;
2536             locale_found = True;
2537             break;
2538          }
2539          if (exportTargets[n] == COMPOUND_TEXT) c_text_found = True;
2540          if (exportTargets[n] == XA_STRING) string_found = True;
2541          if (exportTargets[n] == TEXT) text_found = True;
2542        }
2543
2544        n = 0;
2545        if (locale_found || c_text_found || string_found || text_found) {
2546          if (!locale_found) {
2547             if (c_text_found)
2548                transferEntries[0].target = COMPOUND_TEXT;
2549             else if (string_found)
2550                transferEntries[0].target = XA_STRING;
2551             else
2552                transferEntries[0].target = TEXT;
2553          }
2554
2555          if ( cb->operation & (XmDROP_COPY|XmDROP_MOVE) ) {
2556                 XtSetArg(args[n], XmNdropTransfers, transferList); n++;
2557                 XtSetArg(args[n], XmNnumDropTransfers, numTransfers); n++;
2558          } else {
2559                 XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
2560                 XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
2561          }
2562        } else {
2563          XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
2564          XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
2565        }
2566        dropDestroyCB->closure = (XtPointer) clientData; 
2567        XtSetArg(args[n], XmNdestroyCallback, dropDestroyCB); n++;
2568        XtSetArg(args[n], XmNtransferProc, DropTransferCallback); n++;
2569     }
2570     SetDropContext(w);
2571     XmDropTransferStart(drag_cont, args, n);
2572 }
2573
2574 /* ARGSUSED */
2575 static void
2576 DropProcCallback(
2577         Widget w,
2578         XtPointer client,
2579         XtPointer call )
2580 {
2581     XmDropProcCallbackStruct *cb = (XmDropProcCallbackStruct *) call;
2582
2583     if (cb->dropAction != XmDROP_HELP) {
2584        HandleDrop(w, cb);
2585     } else {
2586        Arg args[2];
2587
2588        XtSetArg(args[0], XmNtransferStatus, XmTRANSFER_FAILURE);
2589        XtSetArg(args[1], XmNnumDropTransfers, 0);
2590        XmDropTransferStart(cb->dragContext, args, 2);
2591     }
2592 }
2593
2594 static void
2595 RegisterDropSite(
2596         Widget w )
2597 {
2598     Atom targets[4];
2599     Arg args[10];
2600     int n;
2601     char * tmp_string = "ABC";  /* these are characters in XPCS, so... safe */
2602     XTextProperty tmp_prop;
2603     int status = 0;
2604
2605     tmp_prop.value = NULL;
2606     status = XmbTextListToTextProperty(XtDisplay(w), &tmp_string, 1,
2607                                       (XICCEncodingStyle)XTextStyle, &tmp_prop);
2608     if (status == Success)
2609        targets[0] = tmp_prop.encoding;
2610     else
2611        targets[0] = 99999; /* XmbTextList... should never fail for XPCS
2612                             * characters.  But just in case someones
2613                             * Xlib is broken, this prevents a core dump.
2614                             */
2615
2616     if (tmp_prop.value != NULL) XFree((char *)tmp_prop.value);
2617
2618     targets[1] = XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False);
2619     targets[2] = XA_STRING;
2620     targets[3] = XmInternAtom(XtDisplay(w), "TEXT", False);
2621
2622     n = 0;
2623     XtSetArg(args[n], XmNimportTargets, targets); n++;
2624     XtSetArg(args[n], XmNnumImportTargets, 4); n++;
2625     /* XtSetArg(args[n], XmNdragProc, DragProcCallback); n++; */
2626     XtSetArg(args[n], XmNdropProc, DropProcCallback); n++;
2627     XmDropSiteRegister(w, args, n);
2628 }
2629
2630
2631 /*
2632  * DRAG SITE code
2633  */
2634
2635 /* ARGSUSED */
2636 static void
2637 StartDrag(
2638         Widget w,
2639         XEvent *event,
2640         String *params,
2641         Cardinal *num_params )
2642 {
2643     DtTermPrimitiveWidget  tw = (DtTermPrimitiveWidget) w;
2644     Atom targets[4];
2645     char * tmp_string = "ABC";  /* these are characters in XPCS, so... safe */
2646     XTextProperty tmp_prop;
2647     int status = 0;
2648     Cardinal num_targets = 0;
2649     Widget drag_icon;
2650     Arg args[10];
2651     int n = 0;
2652
2653     tmp_prop.value = NULL;
2654     status = XmbTextListToTextProperty(XtDisplay(w), &tmp_string, 1,
2655                                       (XICCEncodingStyle)XTextStyle, &tmp_prop);
2656     if (status == Success)
2657        targets[num_targets++] = tmp_prop.encoding;
2658     else
2659        targets[num_targets++] = 99999; /* XmbTextList...  should never fail
2660                                         * for XPCS characters.  But just in
2661                                         * case someones Xlib is broken,
2662                                         * this prevents a core dump.
2663                                         */
2664
2665     if (tmp_prop.value != NULL) XFree((char *)tmp_prop.value);
2666
2667     targets[num_targets++] = XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False);
2668     targets[num_targets++] = XA_STRING;
2669     targets[num_targets++] = XmInternAtom(XtDisplay(w), "TEXT", False);
2670
2671     drag_icon = (Widget) XmeGetTextualDragIcon(w);
2672
2673     n = 0;
2674     XtSetArg(args[n], XmNcursorBackground, tw->core.background_pixel);  n++;
2675     XtSetArg(args[n], XmNcursorForeground, tw->primitive.foreground);  n++;
2676     XtSetArg(args[n], XmNsourceCursorIcon, drag_icon);  n++; 
2677     XtSetArg(args[n], XmNexportTargets, targets);  n++;
2678     XtSetArg(args[n], XmNnumExportTargets, num_targets);  n++;
2679     XtSetArg(args[n], XmNconvertProc, _DtTermPrimSelectConvert);  n++;
2680     XtSetArg(args[n], XmNclientData, w);  n++;
2681     XtSetArg(args[n], XmNdragOperations, ( XmDROP_COPY)); n++;
2682     (void) XmDragStart(w, event, args, n);
2683 }
2684
2685 static Position
2686 GetXFromPos(Widget w, XmTextPosition pos)
2687 {
2688    DtTermPrimitiveWidget  tw = (DtTermPrimitiveWidget) w;
2689    DtTermPrimData tpd = tw->term.tpd;
2690    TermBuffer pb;
2691    short row,col;
2692    TermCharInfoRec charInfoRec ;
2693    
2694    posToBufferRowCol(tw,pos,&pb,&row,&col) ;
2695    return(tpd->offsetX+col*tpd->cellWidth);
2696 }
2697
2698 /* ARGSUSED */
2699 void
2700 _DtTermPrimSelectProcessBDrag(
2701         Widget w,
2702         XEvent *event,
2703         char **params,
2704         Cardinal *num_params )
2705 {
2706     DtTermPrimitiveWidget  tw = (DtTermPrimitiveWidget) w;
2707     TermSelectInfo  selectInfo =
2708                     ((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
2709     XmTextPosition position, left, right;
2710     Position left_x, left_y, right_x, right_y;
2711     /* InputData data = tw->text.input->data; */
2712
2713     selectInfo->cancel = False;
2714     position = xyToPos(tw, event->xbutton.x, event->xbutton.y);
2715
2716     if (_DtTermPrimSelectGetSelection(w, &left, &right) &&
2717         (right != left)) {
2718        if ((position > left && position < right) 
2719          || (position == left &&
2720                event->xbutton.x > GetXFromPos(w, left))
2721          || (position == right &&
2722                event->xbutton.x < GetXFromPos(w, right))) {
2723            selectInfo->sel_start = False;
2724            StartDrag(w, event, params, num_params);
2725          }
2726         else
2727          {
2728           selectInfo->sel_start = True ;
2729          }
2730      }
2731     else selectInfo->sel_start = True ;
2732 }
2733
2734
2735 /* This is the menu interface for copy clipboard */
2736 Boolean 
2737 _DtTermPrimSelectCopyClipboard
2738 (
2739     Widget w,
2740     Time copy_time
2741 )
2742 {
2743     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
2744     XmTextPosition begin;
2745     XmTextPosition end;
2746
2747     char *selected_string = NULL;                  /* text selection */
2748     long item_id = 0L;                             /* clipboard item id */
2749     long data_id = 0L;                             /* clipboard data id */
2750     int status;                                    /* clipboard status  */
2751     XmString clip_label;
2752     XTextProperty tmp_prop;
2753     Display *display = XtDisplay(w);
2754     Window window = XtWindow(w);
2755     char *atom_name;
2756
2757     if ( _DtTermPrimSelectGetSelection(w, &begin, &end) && begin != end ) {
2758       selected_string = getString(w, begin, end, False);
2759      }
2760     /*
2761      * Using the Xm clipboard facilities,
2762      * copy the selected text to the clipboard
2763      */
2764     tmp_prop.value = NULL;
2765     if (selected_string != NULL) {
2766        clip_label = XmStringCreateLocalized ("XM_TERM");
2767        /* start copy to clipboard */
2768        status = XmClipboardStartCopy(display, window, clip_label, copy_time,
2769                        w, NULL, &item_id);
2770
2771        if (status != ClipboardSuccess) {
2772          XtFree(selected_string);
2773          XmStringFree(clip_label);
2774          return False;
2775        }
2776  
2777        status = XmbTextListToTextProperty(display, &selected_string, 1,
2778                             (XICCEncodingStyle)XStdICCTextStyle,
2779                             &tmp_prop);
2780
2781        if (status != Success && status <= 0) {
2782           XmClipboardCancelCopy(display, window, item_id);
2783           XtFree(selected_string);
2784           XmStringFree(clip_label);
2785           return False;
2786         }
2787
2788        atom_name = XGetAtomName(display, tmp_prop.encoding);
2789
2790        /* move the data to the clipboard */
2791        status = XmClipboardCopy(display, window, item_id, atom_name,
2792                   (XtPointer)tmp_prop.value, tmp_prop.nitems,
2793                   0, &data_id);
2794
2795        XtFree(atom_name);
2796
2797        if (status != ClipboardSuccess) {
2798             XmClipboardCancelCopy(display, window, item_id);
2799             XFree((char*)tmp_prop.value);
2800             XmStringFree(clip_label);
2801             return False;
2802         }
2803
2804        /* end the copy to the clipboard */
2805        status = XmClipboardEndCopy (display, window, item_id);
2806
2807        XtFree((char*)tmp_prop.value);
2808        XmStringFree(clip_label);
2809
2810        if (status != ClipboardSuccess) return False;
2811      } else
2812          return False;
2813
2814    if (selected_string!=NULL) 
2815         XtFree(selected_string);
2816    return True;
2817 }
2818
2819 /* This is the event interface for copy clipboard */
2820 void
2821 _DtTermPrimSelectCopyClipboardEventIF
2822 (
2823     Widget w,
2824     XEvent *event,
2825     String *params,
2826     Cardinal *num_params
2827 )
2828 {
2829     _DtTermPrimSelectCopyClipboard(w,event->xkey.time) ;
2830 }
2831
2832 /*
2833  * Retrieves the current data from the clipboard
2834  * and paste it at the current cursor position
2835  */
2836 Boolean 
2837 _DtTermPrimSelectPasteClipboard
2838 (
2839       Widget w 
2840 )
2841 {
2842       XmTextPosition sel_left = 0;
2843       XmTextPosition sel_right = 0;
2844       XmTextPosition paste_pos_left, paste_pos_right, cursorPos;
2845       int status;                                /* clipboard status        */
2846       char * buffer;                             /* temporary text buffer   */
2847       unsigned long length;                      /* length of buffer        */
2848       unsigned long outlength = 0L;              /* length of bytes copied  */
2849       long private_id = 0L;                      /* id of item on clipboard */
2850       Boolean dest_disjoint = True;
2851       XmTextBlockRec block, newblock;
2852       Display *display = XtDisplay(w);
2853       Window window = XtWindow(w);
2854       Boolean get_ct = False;
2855       Boolean freeBlock;
2856       XTextProperty tmp_prop;
2857       int malloc_size = 0;
2858       int num_vals;
2859       char **tmp_value;
2860       char * total_tmp_value = NULL;
2861       int i;
2862
2863       status = XmClipboardInquireLength(display, window, "STRING", &length);
2864
2865       if (status == ClipboardNoData || length == 0) {
2866          status = XmClipboardInquireLength(display, window, "COMPOUND_TEXT",
2867                                            &length);
2868          if (status == ClipboardNoData || length == 0) return False;
2869          get_ct = True;
2870       }
2871
2872       /* malloc length of clipboard data */
2873       buffer = XtMalloc((unsigned) length);
2874
2875       if (!get_ct) {
2876          status = XmClipboardRetrieve(display, window, "STRING", buffer,
2877                                        length, &outlength, &private_id);
2878       } else {
2879          status = XmClipboardRetrieve(display, window, "COMPOUND_TEXT",
2880                                        buffer, length, &outlength, &private_id);
2881       }
2882
2883
2884       if (status != ClipboardSuccess) {
2885         XmClipboardEndRetrieve(display, window);
2886         XtFree(buffer);
2887         return False;
2888       }
2889
2890       tmp_prop.value = (unsigned char *) buffer;
2891       if (!get_ct)
2892          tmp_prop.encoding = XA_STRING;
2893       else
2894          tmp_prop.encoding = XmInternAtom(display, "COMPOUND_TEXT", False);
2895
2896       tmp_prop.format = 8;
2897       tmp_prop.nitems = outlength;
2898       num_vals = 0;
2899
2900       status = XmbTextPropertyToTextList(display, &tmp_prop, &tmp_value,
2901                                          &num_vals);
2902
2903      /* if no conversions, num_vals doesn't change */
2904       if (num_vals && (status == Success || status > 0)) {
2905          for (i = 0; i < num_vals ; i++)
2906              malloc_size += strlen(tmp_value[i]);
2907
2908          total_tmp_value = XtMalloc ((unsigned) malloc_size + 1);
2909          total_tmp_value[0] = '\0';
2910          for (i = 0; i < num_vals ; i++)
2911             strcat(total_tmp_value, tmp_value[i]);
2912          block.ptr = total_tmp_value;
2913          block.length = strlen(total_tmp_value);
2914          block.format = XmFMT_8_BIT;
2915          XFreeStringList(tmp_value);
2916       } else {
2917          malloc_size = 1; /* to force space to be freed */
2918          total_tmp_value = XtMalloc ((unsigned)1);
2919          *total_tmp_value = '\0';
2920          block.ptr = total_tmp_value;
2921          block.length = 0;
2922          block.format = XmFMT_8_BIT;
2923       }
2924
2925       /* add new text */
2926       if ( block.length )
2927        {
2928          char  *pChar, *pCharEnd, *pCharFollow;
2929
2930          pCharEnd    = block.ptr + block.length;
2931          pCharFollow = (char *)block.ptr;
2932
2933          for (pChar = (char *)block.ptr; pChar < pCharEnd; pChar++)
2934          {
2935              if (*pChar == '\n')
2936              {
2937                  *pChar = '\r';
2938                  DtTermSubprocSend(w, (unsigned char *) pCharFollow,
2939                                pChar - pCharFollow + 1);
2940                  pCharFollow = pChar + 1;
2941              }
2942          }
2943          if (pCharFollow < pCharEnd)
2944          {
2945              DtTermSubprocSend(w, (unsigned char *) pCharFollow,
2946                            pCharEnd - pCharFollow);
2947          }
2948       }
2949      XtFree(buffer);
2950      if (malloc_size != 0) XtFree(total_tmp_value);
2951
2952      (void) _DtTermPrimCursorOn(w);
2953 }
2954
2955 /* This is the event interface for paste clipboard */
2956 void    
2957 _DtTermPrimSelectPasteClipboardEventIF
2958 (
2959     Widget w,
2960     XEvent *event,
2961     String *params,
2962     Cardinal *num_params
2963 )
2964 {
2965     _DtTermPrimSelectPasteClipboard(w) ;
2966 }
2967
2968 /*
2969  *  This is for the SUN two button mouse
2970  */
2971 static Bool
2972 LookForButton (
2973         Display * display,
2974         XEvent * event,
2975         XPointer arg)
2976 {
2977
2978 #define DAMPING 5
2979 #define ABS_DELTA(x1, x2) (x1 < x2 ? x2 - x1 : x1 - x2)
2980
2981     if( event->type == MotionNotify)  {
2982         XEvent * press = (XEvent *) arg;
2983
2984         if (ABS_DELTA(press->xbutton.x_root, event->xmotion.x_root) > DAMPING ||
2985             ABS_DELTA(press->xbutton.y_root, event->xmotion.y_root) > DAMPING)
2986             return(True);
2987     }
2988     else if (event->type == ButtonRelease)
2989         return(True);
2990     return(False);
2991 }
2992
2993 /* ARGSUSED */
2994 static Boolean
2995 XmTestInSelection(
2996         Widget w,
2997         XEvent *event )
2998 {
2999     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
3000     TermSelectInfo  selectInfo = tw->term.tpd->selectInfo;
3001     XmTextPosition position, left, right;
3002     Position left_x, right_x, dummy;
3003
3004     position = xyToPos(tw, event->xbutton.x, event->xbutton.y);
3005
3006     if (!(_DtTermPrimSelectGetSelection(w, &left, &right) &&
3007         left != right && (position > left && position < right) 
3008          || (position == left &&
3009                event->xbutton.x > GetXFromPos(w, left))
3010          || (position == right &&
3011                event->xbutton.x < GetXFromPos(w, right))) 
3012          ||
3013            /* or if it is part of a multiclick sequence */
3014            (event->xbutton.time > selectInfo->lastTime &&
3015             event->xbutton.time - selectInfo->lastTime  <
3016               XtGetMultiClickTime(XtDisplay((Widget)w))) )
3017         return(False);
3018     else {
3019         /* The determination of whether this is a transfer drag cannot be made
3020            until a Motion event comes in.  It is not a drag as soon as a
3021            ButtonUp event happens or the MultiClickTimeout expires. */
3022         XEvent new;
3023
3024         XPeekIfEvent(XtDisplay(w), &new, LookForButton, (XPointer)event);
3025         switch (new.type)  {
3026             case MotionNotify:
3027                return(True);
3028                break;
3029             case ButtonRelease:
3030                return(False);
3031                break;
3032         }
3033         return(False);
3034     }
3035 }
3036
3037 #define SELECTION_ACTION        0
3038 #define TRANSFER_ACTION         1
3039
3040 /* ARGSUSED */
3041 void
3042 _DtTermPrimSelect2ButtonMouse(
3043         Widget w,
3044         XEvent *event,
3045         char **params,
3046         Cardinal *num_params )
3047 {
3048    /*  This action happens when Button1 is pressed and the Selection
3049        and Transfer are integrated on Button1.  It is passed two
3050        parameters: the action to call when the event is a selection,
3051        and the action to call when the event is a transfer. */
3052
3053    if (*num_params != 2 /* || !XmIsTextField(w) */)
3054       return;
3055    if (XmTestInSelection(w, event))
3056       XtCallActionProc(w, params[TRANSFER_ACTION], event, params, *num_params);
3057    else
3058       XtCallActionProc(w, params[SELECTION_ACTION], event, params, *num_params);
3059 }
3060
3061
3062 void
3063 _DtTermPrimSelectProcessCancel(
3064         Widget w,
3065         XEvent *event,
3066         String *params,
3067         Cardinal *num_params )
3068 {
3069     DtTermPrimitiveWidget   tw          = (DtTermPrimitiveWidget)w;
3070     TermSelectInfo  selectInfo = tw->term.tpd->selectInfo;
3071     XmTextPosition left_x, right_x;
3072
3073     XmParentInputActionRec  p_event ;
3074
3075     if (!tw->term.allowOsfKeysyms) {
3076       _DtTermPrimActionKeyInput(w,event,params,num_params);
3077       return;
3078     }
3079       
3080     selectInfo->cancel = True ;
3081
3082     /* turn off the cursor */
3083     _DtTermPrimCursorOff(w);
3084
3085     /* reset to origLeft and origRight */
3086     setSelection (tw, selectInfo->origBegin, selectInfo->origEnd, 
3087                               event->xkey.time, False) ;
3088
3089     /* turn on the cursor */
3090     _DtTermPrimCursorOn(w);
3091
3092     if (selectInfo->selectID) {
3093        XtRemoveTimeOut(selectInfo->selectID);
3094        selectInfo->selectID = 0;
3095     }
3096 }