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