3080 lines
87 KiB
C
3080 lines
87 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* *
|
|
* (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company *
|
|
* (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
|
|
* (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. *
|
|
* (c) Copyright 1993, 1994, 1996 Novell, Inc. *
|
|
* (c) Copyright 1995, 1996 Digital Equipment Corporation. *
|
|
* (c) Copyright 1996 FUJITSU LIMITED. *
|
|
* (c) Copyright 1996 Hitachi. *
|
|
*/
|
|
|
|
#include "TermHeader.h"
|
|
#include <X11/Xatom.h>
|
|
#include <Xm/Xm.h>
|
|
#include <Xm/AtomMgr.h>
|
|
#include <Xm/CutPaste.h>
|
|
#include <Xm/XmPrivate.h>
|
|
#include <Xm/ScrollBarP.h>
|
|
#include "TermPrimAction.h"
|
|
#include "TermPrimDebug.h"
|
|
#include "TermPrimP.h"
|
|
#include "TermPrimData.h"
|
|
#include "TermPrimRender.h"
|
|
#include "TermPrimSelectP.h"
|
|
#include "TermPrimBufferP.h"
|
|
#include <Xm/DropSMgr.h>
|
|
#include <Xm/DropTrans.h>
|
|
#include <ctype.h>
|
|
#include <wctype.h>
|
|
|
|
/* This is for Sun's two button mouse */
|
|
|
|
static char _DtTermEventBindingsCDE[] = "\
|
|
~c ~s ~m ~a <Btn1Down>:process-press(grab-focus,process-bdrag)\n\
|
|
~c s ~m ~a <Btn1Down>:process-press(extend-start,process-bdrag)\n\
|
|
~c ~m ~a <Btn1Motion>:select-adjust()\n\
|
|
~c ~m ~a <Btn1Up>:extend-end()";
|
|
static char _DtTermEventBindingsCDEBtn2[] = "\
|
|
<Btn2Down>:extend-start()\n\
|
|
<Btn2Motion>:select-adjust()\n\
|
|
<Btn2Up>:extend-end()";
|
|
|
|
static
|
|
XmTextScanType defaultScanArray[] =
|
|
{
|
|
XmSELECT_POSITION,
|
|
XmSELECT_WORD,
|
|
XmSELECT_LINE,
|
|
XmSELECT_ALL
|
|
};
|
|
|
|
static void RegisterDropSite( Widget w );
|
|
static void doExtendedSelection (Widget w,Time eventTime);
|
|
|
|
/*
|
|
** Get the current server time (I ripped this off from Xm/TextIn.c).
|
|
*/
|
|
static Time
|
|
getServerTime
|
|
(
|
|
Widget w
|
|
)
|
|
{
|
|
XEvent event;
|
|
EventMask shellMask;
|
|
|
|
while(!XtIsShell(w))
|
|
{
|
|
w = XtParent(w);
|
|
}
|
|
|
|
shellMask = XtBuildEventMask(w);
|
|
|
|
if (!(shellMask & PropertyChangeMask))
|
|
{
|
|
XSelectInput(XtDisplay(w), XtWindow(w), shellMask | PropertyChangeMask);
|
|
}
|
|
|
|
XChangeProperty(XtDisplay(w), XtWindow(w), XA_WM_HINTS, XA_WM_HINTS,
|
|
32, PropModeAppend, (unsigned char *)NULL, 0);
|
|
|
|
XWindowEvent(XtDisplay(w), XtWindow(w), PropertyChangeMask, &event);
|
|
|
|
if (!(shellMask & PropertyChangeMask))
|
|
{
|
|
XSelectInput(XtDisplay(w), XtWindow(w), shellMask);
|
|
}
|
|
|
|
return(event.xproperty.time);
|
|
}
|
|
|
|
|
|
static void
|
|
setScanType
|
|
(
|
|
Widget w,
|
|
XEvent *event
|
|
)
|
|
{
|
|
TermSelectInfo selectInfo =
|
|
((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
|
|
int multiClickTime;
|
|
int i;
|
|
|
|
multiClickTime = XtGetMultiClickTime(XtDisplay(w));
|
|
|
|
if (event->xbutton.time > selectInfo->lastTime &&
|
|
event->xbutton.time - selectInfo->lastTime <
|
|
(multiClickTime == 200 ? 500 : multiClickTime))
|
|
{
|
|
i = 0;
|
|
while (i < selectInfo->scanArraySize &&
|
|
selectInfo->scanArray[i] != selectInfo->scanType)
|
|
{
|
|
i++;
|
|
}
|
|
|
|
if (++i >= selectInfo->scanArraySize)
|
|
{
|
|
i = 0;
|
|
}
|
|
selectInfo->scanType = selectInfo->scanArray[i];
|
|
}
|
|
else
|
|
{
|
|
/* single-click event */
|
|
selectInfo->scanType = selectInfo->scanArray[0];
|
|
}
|
|
|
|
selectInfo->lastTime = event->xbutton.time;
|
|
}
|
|
|
|
/*
|
|
** convert a row,col pair into the equivalent XmTextPosition
|
|
**
|
|
** NOTE:
|
|
** this routine assumes that the calling routine as already checked
|
|
** row and col to insure that they are within the bounds of the terminal
|
|
** buffer (see _DtTermPrimSelectGrabFocus)
|
|
*/
|
|
XmTextPosition
|
|
rowColToPos
|
|
(
|
|
DtTermPrimitiveWidget tw,
|
|
short row,
|
|
short col
|
|
)
|
|
{
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
return(((tpd->selectInfo->columns + 1) *
|
|
(row + tpd->lastUsedHistoryRow)) + col);
|
|
}
|
|
|
|
/*
|
|
** getSelection
|
|
*/
|
|
Boolean
|
|
_DtTermPrimSelectGetSelection
|
|
(
|
|
Widget w,
|
|
XmTextPosition *begin,
|
|
XmTextPosition *end
|
|
)
|
|
{
|
|
TermSelectInfo selectInfo =
|
|
((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
|
|
|
|
if (selectInfo->ownPrimary &&
|
|
(selectInfo->begin <= selectInfo->end) &&
|
|
selectInfo->begin >= 0)
|
|
{
|
|
*begin = selectInfo->begin;
|
|
*end = selectInfo->end;
|
|
return(True);
|
|
}
|
|
else
|
|
{
|
|
*begin = 0;
|
|
*end = 0;
|
|
selectInfo->ownPrimary = False;
|
|
return(False);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** convert an x,y pair into the appropriate text position
|
|
**
|
|
** Since positions count the number of inter-character spaces, there is
|
|
** one more x position on a line than columns on a line; xPos can be in
|
|
** the range (0, selectInfo->columns + 1). The same is true for yPos,
|
|
** it can be in the range (0, tpd->lastUsedRow - tpd->topRow - 1)
|
|
**
|
|
** In the case that we have a history buffer to deal with, text positions
|
|
** in the history buffer are forced to come before positions in the term
|
|
** buffer.
|
|
**
|
|
** NOTE:
|
|
** this routine assumes that the calling routine as already checked
|
|
** x and y to insure that they are within the bounds of the terminal
|
|
** window (see _DtTermPrimSelectGrabFocus)
|
|
** NOTE:
|
|
** I believe I'm now doing all checking in this routine for confining
|
|
** the x,y to the window. Disregard the previous note. TMH
|
|
*/
|
|
static
|
|
XmTextPosition
|
|
xyToPos
|
|
(
|
|
DtTermPrimitiveWidget tw,
|
|
int x, /* pixel */
|
|
int y /* pixel */
|
|
)
|
|
{
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
TermBuffer tb;
|
|
short row;
|
|
short yPos;
|
|
short xPos;
|
|
static short oldYPos = -1;
|
|
static short oldXPos = -1;
|
|
|
|
|
|
if ( x<0) x = 0;
|
|
if ( x > (int) tw->core.width) x = tw->core.width;
|
|
/*
|
|
** convert pixel units to character positions
|
|
*/
|
|
yPos = (MAX(0, y) - tpd->offsetY) / tpd->cellHeight;
|
|
|
|
/*
|
|
** yPos cannot exceed the buffer or screen
|
|
*/
|
|
yPos = MIN(yPos, MIN(tw->term.rows, tpd->lastUsedRow - tpd->topRow) - 1) +
|
|
tpd->topRow;
|
|
|
|
/*
|
|
** consider the possibility that we have a history buffer
|
|
*/
|
|
if (tpd->useHistoryBuffer)
|
|
{
|
|
if (yPos < 0)
|
|
{
|
|
/*
|
|
** yPos is not in the history buffer (order is important,
|
|
** step 2 must come before step 3):
|
|
** 1) point to history buffer
|
|
** 2) adjust yPos
|
|
** 3) decide which row of the buffer we are concerned
|
|
** with
|
|
*/
|
|
tb = tpd->historyBuffer;
|
|
yPos += tpd->lastUsedHistoryRow;
|
|
row = yPos;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** yPos is not in the history buffer (order is important,
|
|
** step 2 must come before step 3):
|
|
** 1) point to term buffer
|
|
** 2) decide which row of the buffer we are concerned
|
|
** with
|
|
** 3) adjust yPos
|
|
*/
|
|
tb = tpd->termBuffer;
|
|
row = yPos;
|
|
yPos += tpd->lastUsedHistoryRow;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tb = tpd->termBuffer;
|
|
row = yPos;
|
|
}
|
|
|
|
xPos = (((x - tpd->offsetX) + (tpd->cellWidth / 2)) / tpd->cellWidth) ;
|
|
|
|
if ( MB_CUR_MAX > 1 ) /* check if xPos splits a 2 col char */
|
|
{
|
|
TermCharInfoRec charInfoRec ;
|
|
if (_DtTermPrimGetCharacterInfo(tb,row,xPos,&charInfoRec) )
|
|
{
|
|
if (charInfoRec.width == 2 && charInfoRec.startCol != xPos)
|
|
{
|
|
if (xPos*tpd->cellWidth < x - tpd->offsetX )
|
|
xPos++ ; /* set to right of char */
|
|
else
|
|
xPos-- ; /* set to left of char */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ((yPos != oldYPos) || (xPos != oldXPos))
|
|
{
|
|
oldYPos = yPos;
|
|
oldXPos = xPos;
|
|
}
|
|
return (((selectInfo->columns + 1) * yPos) + xPos);
|
|
}
|
|
|
|
/*
|
|
* Takes a linear position and return buffer, row, and col.
|
|
* Since positions are between characters, this returns the col to
|
|
* right of the position.
|
|
*/
|
|
static void
|
|
posToBufferRowCol
|
|
(
|
|
DtTermPrimitiveWidget tw,
|
|
XmTextPosition pos,
|
|
TermBuffer *pb,
|
|
short *row,
|
|
short *col
|
|
)
|
|
{
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
short lrow, lcol;
|
|
|
|
lrow = pos / (selectInfo->columns + 1);
|
|
lcol = pos - (lrow * (selectInfo->columns + 1));
|
|
|
|
if ( tpd->useHistoryBuffer ) lrow -= tpd->lastUsedHistoryRow ;
|
|
|
|
if ( lrow < 0 ) { /* in history buffer */
|
|
*pb=tw->term.tpd->historyBuffer ;
|
|
lrow += tpd->lastUsedHistoryRow ;
|
|
}
|
|
else
|
|
{
|
|
*pb = tpd->termBuffer ;
|
|
}
|
|
*row = lrow ;
|
|
*col = lcol ;
|
|
}
|
|
|
|
/*
|
|
* Takes a buffer, row and column and returns the linear position.
|
|
*/
|
|
static XmTextPosition
|
|
bufferRowColToPos
|
|
(
|
|
DtTermPrimitiveWidget tw,
|
|
TermBuffer pb,
|
|
short row,
|
|
short col
|
|
)
|
|
{
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
short lrow, lcol;
|
|
XmTextPosition pos;
|
|
|
|
/* assume row, col in the history buffer or there is no history */
|
|
pos = (tpd->selectInfo->columns + 1) * row + col;
|
|
|
|
if ( tpd->useHistoryBuffer && pb == tpd->termBuffer)
|
|
pos += (tpd->selectInfo->columns + 1) * (tpd->lastUsedHistoryRow) ;
|
|
return(pos) ;
|
|
}
|
|
|
|
|
|
static XmTextPosition
|
|
scan
|
|
(
|
|
DtTermPrimitiveWidget tw,
|
|
XmTextPosition scanStart,
|
|
XmTextScanType scanType,
|
|
TermScanDirection scanDir,
|
|
int count,
|
|
Boolean inclusive
|
|
)
|
|
{
|
|
int i;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
XmTextPosition position = scanStart;
|
|
short row;
|
|
short col;
|
|
TermBuffer pb ;
|
|
|
|
|
|
switch(scanType)
|
|
{
|
|
case XmSELECT_POSITION:
|
|
posToBufferRowCol(tw, position, &pb, &row, &col) ;
|
|
if ( col > _DtTermPrimBufferGetLineWidth(pb, row) )
|
|
{
|
|
col = selectInfo->columns + 1;
|
|
position = bufferRowColToPos(tw,pb,row,col) ;
|
|
}
|
|
break;
|
|
case XmSELECT_WORD:
|
|
{
|
|
short width;
|
|
posToBufferRowCol(tw, position, &pb, &row, &col) ;
|
|
width = _DtTermPrimBufferGetLineWidth(pb,row);
|
|
if ( col > width ) break;
|
|
|
|
if ( MB_CUR_MAX > 1 )
|
|
{
|
|
TermCharInfoRec charInfoRec ;
|
|
|
|
_DtTermPrimGetCharacterInfo(pb,row,col,&charInfoRec);
|
|
col = charInfoRec.startCol ; /* align first */
|
|
|
|
switch(scanDir)
|
|
{
|
|
case scanLeft:
|
|
_DtTermPrimGetCharacterInfo(pb,row,col?--col:0,&charInfoRec);
|
|
while( !iswspace(*(wchar_t *)charInfoRec.u.pwc) &&
|
|
((col=charInfoRec.startCol-1)>=0) )
|
|
{
|
|
_DtTermPrimGetCharacterInfo(pb,row,col,&charInfoRec) ;
|
|
}
|
|
col ++ ;
|
|
break;
|
|
case scanRight:
|
|
_DtTermPrimGetCharacterInfo(pb,row,col,&charInfoRec);
|
|
while(++col<=width && !iswspace(*(wchar_t *)charInfoRec.u.pwc))
|
|
_DtTermPrimGetCharacterInfo(pb,row,col,&charInfoRec);
|
|
col--;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char pbuf[10];
|
|
switch(scanDir)
|
|
{
|
|
case scanLeft:
|
|
_DtTermPrimBufferGetText(pb, row, col?--col:0, 1, pbuf, False);
|
|
while( !isspace(*pbuf) && --col >= 0)
|
|
_DtTermPrimBufferGetText(pb, row, col, 1, pbuf, False );
|
|
col++ ;
|
|
break;
|
|
case scanRight:
|
|
_DtTermPrimBufferGetText(pb, row, col, 1, pbuf, False);
|
|
while( ++col <= width && !isspace(*pbuf))
|
|
_DtTermPrimBufferGetText(pb, row, col, 1, pbuf, False );
|
|
col--;
|
|
break;
|
|
}
|
|
}
|
|
position = bufferRowColToPos(tw,pb,row,col) ;
|
|
}
|
|
break;
|
|
case XmSELECT_LINE:
|
|
{
|
|
|
|
posToBufferRowCol(tw, position, &pb, &row, &col) ;
|
|
col = 0;
|
|
switch(scanDir)
|
|
{
|
|
case scanLeft:
|
|
break;
|
|
case scanRight:
|
|
col = selectInfo->columns + 1;
|
|
break;
|
|
}
|
|
position = bufferRowColToPos(tw,pb,row,col) ;
|
|
}
|
|
break;
|
|
case XmSELECT_ALL:
|
|
switch(scanDir)
|
|
{
|
|
case scanLeft:
|
|
position = 0;
|
|
break;
|
|
case scanRight:
|
|
pb = tpd->termBuffer ;
|
|
row = tpd->lastUsedRow-1;
|
|
col = _DtTermPrimBufferGetLineWidth(pb,row) ;
|
|
position = bufferRowColToPos(tw,pb,row,col) ;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return(position);
|
|
}
|
|
|
|
/*
|
|
** refresh all text from start up to stop
|
|
**
|
|
** NOTE:
|
|
** We assume that start is always <= than stop
|
|
*/
|
|
void
|
|
_DtTermPrimRenderRefreshTextLinear
|
|
(
|
|
Widget w,
|
|
XmTextPosition start,
|
|
XmTextPosition stop
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
short startRow, startCol;
|
|
short stopRow , stopCol;
|
|
|
|
|
|
/*
|
|
** Turn XmTextPosition into a row and column
|
|
*/
|
|
startRow = start / (selectInfo->columns + 1);
|
|
startCol = start - (startRow * (selectInfo->columns + 1));
|
|
stopRow = stop / (selectInfo->columns + 1);
|
|
stopCol = stop - (stopRow * (selectInfo->columns + 1));
|
|
|
|
/*
|
|
** Accomodate the history buffer as necessary
|
|
*/
|
|
if (tpd->useHistoryBuffer)
|
|
{
|
|
startRow -= tpd->lastUsedHistoryRow;
|
|
stopRow -= tpd->lastUsedHistoryRow;
|
|
}
|
|
|
|
/*
|
|
** Now adjust for the top of the window
|
|
*/
|
|
startRow -= tpd->topRow;
|
|
stopRow -= tpd->topRow;
|
|
|
|
|
|
/*
|
|
** refresh the first (and possibly only) line
|
|
*/
|
|
if (startRow == stopRow)
|
|
{
|
|
_DtTermPrimRefreshText((Widget)tw, startCol, startRow,
|
|
stopCol, startRow);
|
|
return;
|
|
}
|
|
_DtTermPrimRefreshText((Widget)tw, startCol, startRow,
|
|
selectInfo->columns - 1, startRow);
|
|
|
|
/*
|
|
** refresh the middle block (if there is one)
|
|
*/
|
|
if (startRow++ < stopRow)
|
|
{
|
|
_DtTermPrimRefreshText((Widget)tw, 0, startRow,
|
|
selectInfo->columns - 1, stopRow - 1);
|
|
}
|
|
|
|
/*
|
|
** refresh the last line
|
|
*/
|
|
_DtTermPrimRefreshText((Widget)tw, 0, stopRow, stopCol, stopRow);
|
|
|
|
}
|
|
|
|
|
|
static void
|
|
setSelection
|
|
(
|
|
DtTermPrimitiveWidget tw,
|
|
XmTextPosition begin,
|
|
XmTextPosition end,
|
|
Time selectTime,
|
|
Boolean fromLoseSelection
|
|
)
|
|
{
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
XmTextPosition oldBegin, oldEnd;
|
|
Boolean disJoint; /* true if new and current are disjoint */
|
|
short selectLineBegin;
|
|
short selectColBegin;
|
|
short selectLineEnd;
|
|
short selectColEnd;
|
|
|
|
Debug('c', fprintf(stderr, ">>setSelection() starting\n"));
|
|
|
|
if (selectInfo->ownPrimary == False &&
|
|
begin > end)
|
|
{
|
|
Debug('c', fprintf(stderr, ">>setSelection() finishing a\n"));
|
|
return;
|
|
}
|
|
|
|
if (begin < 0)
|
|
{
|
|
begin = 0;
|
|
end = 0;
|
|
}
|
|
|
|
if (selectInfo->ownPrimary)
|
|
{
|
|
/*
|
|
** we own the selection see how much (if any) of the selected
|
|
** area needs to be unhighlighted...
|
|
*/
|
|
if (selectInfo->begin < selectInfo->end)
|
|
{
|
|
/*
|
|
** We own the selection, and its highlighted...
|
|
*/
|
|
if ((end <= selectInfo->begin) ||
|
|
(begin >= selectInfo->end))
|
|
{
|
|
/*
|
|
** The two areas don't intersect, simply clear the old
|
|
** area...
|
|
*/
|
|
Debug('c', fprintf(stderr, " new & old are disjoint\n"));
|
|
selectInfo->ownPrimary = False;
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw,
|
|
selectInfo->begin,
|
|
selectInfo->end - 1);
|
|
selectInfo->ownPrimary = True;
|
|
disJoint = True;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** There is some intersection, save the current begin
|
|
** and end so we can clean things up later.
|
|
*/
|
|
Debug('c', fprintf(stderr, " new & old intersect\n"));
|
|
oldBegin = selectInfo->begin;
|
|
oldEnd = selectInfo->end;
|
|
disJoint = False;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** We own the selection, but nothing is highlighted...
|
|
*/
|
|
disJoint = True;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** we don't own the selection (yet), come up with some reasonable
|
|
** defaults
|
|
*/
|
|
disJoint = True;
|
|
oldBegin = begin;
|
|
oldEnd = end;
|
|
}
|
|
|
|
|
|
selectInfo->begin = begin;
|
|
selectInfo->end = end;
|
|
|
|
if (begin <= end)
|
|
{
|
|
if (selectInfo->ownPrimary == False)
|
|
{
|
|
if (!XtOwnSelection((Widget)tw, XA_PRIMARY, selectTime,
|
|
_DtTermPrimSelectConvert,
|
|
_DtTermPrimSelectLoseSelection,
|
|
(XtSelectionDoneProc) NULL))
|
|
{
|
|
/*
|
|
** XtOwnSelection failed, make a dummy call to setSelection
|
|
** (with begin > end) to clear things up...
|
|
*/
|
|
setSelection(tw, 1, -99, selectTime, False);
|
|
}
|
|
else
|
|
{
|
|
selectInfo->ownPrimary = True;
|
|
selectInfo->primaryTime = selectTime;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** now highlight the currently selected text...
|
|
*/
|
|
if (selectInfo->ownPrimary)
|
|
{
|
|
if (disJoint == True)
|
|
{
|
|
/*
|
|
** the selections are disjoint, simply draw the new one
|
|
*/
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw, begin, end - 1);
|
|
}
|
|
else
|
|
{
|
|
if (begin != oldBegin)
|
|
{
|
|
if (begin < oldBegin)
|
|
{
|
|
/*
|
|
** refresh from the new beginning to the old
|
|
** beginning
|
|
*/
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw, begin,
|
|
oldBegin - 1);
|
|
}
|
|
else if (oldBegin < begin)
|
|
{
|
|
/*
|
|
** refresh from the old beginning to the new
|
|
** beginning
|
|
**
|
|
** NOTE: in this case we want to unhighlight
|
|
** previously selected text, so we
|
|
** temporarily set ownPrimary to false
|
|
*/
|
|
selectInfo->ownPrimary = False;
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw, oldBegin,
|
|
begin - 1);
|
|
selectInfo->ownPrimary = True;
|
|
}
|
|
}
|
|
if (end != oldEnd)
|
|
{
|
|
if (end < oldEnd)
|
|
{
|
|
/*
|
|
** refresh from the new end to the original end
|
|
**
|
|
** NOTE: in this case we want to unhighlight
|
|
** previously selected text, so we
|
|
** temporarily set ownPrimary to false
|
|
*/
|
|
selectInfo->ownPrimary = False;
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw, end,
|
|
oldEnd - 1);
|
|
selectInfo->ownPrimary = True;
|
|
}
|
|
else if (oldEnd < end)
|
|
{
|
|
/*
|
|
** refresh from the old end to the new end.
|
|
*/
|
|
_DtTermPrimRenderRefreshTextLinear((Widget)tw, oldEnd,
|
|
end - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!fromLoseSelection)
|
|
{
|
|
XtDisownSelection((Widget)tw, XA_PRIMARY, selectTime);
|
|
}
|
|
selectInfo->ownPrimary = False;
|
|
}
|
|
|
|
selectLineBegin = selectInfo->begin / (selectInfo->columns + 1);
|
|
selectColBegin = selectInfo->begin % (selectInfo->columns + 1);
|
|
selectLineEnd = (selectInfo->end - 1) / (selectInfo->columns + 1);
|
|
selectColEnd = (selectInfo->end - 1) % (selectInfo->columns + 1);
|
|
|
|
DebugF('c', 1,
|
|
fprintf(stderr, "set selection units: %ld-%ld lines: %d-%d\n",
|
|
selectInfo->begin, selectInfo->end,
|
|
selectLineBegin,
|
|
selectLineEnd));
|
|
if (tw->term.tpd->useHistoryBuffer && tw->term.tpd->lastUsedHistoryRow>0) {
|
|
if (selectLineEnd > tw->term.tpd->lastUsedHistoryRow) {
|
|
(void) _DtTermPrimBufferSetSelectLines(tw->term.tpd->historyBuffer,
|
|
selectLineBegin, selectColBegin,
|
|
tw->term.tpd->lastUsedHistoryRow - 1, selectInfo->columns);
|
|
} else {
|
|
(void) _DtTermPrimBufferSetSelectLines(tw->term.tpd->historyBuffer,
|
|
selectLineBegin, selectColBegin,
|
|
selectLineEnd, selectColEnd);
|
|
}
|
|
selectLineBegin -= tw->term.tpd->lastUsedHistoryRow;
|
|
if (selectLineBegin < 0) {
|
|
selectLineBegin = 0;
|
|
selectColBegin = 0;
|
|
}
|
|
selectLineEnd -= tw->term.tpd->lastUsedHistoryRow;
|
|
}
|
|
|
|
if (selectLineEnd > tw->term.tpd->lastUsedRow) {
|
|
(void) _DtTermPrimBufferSetSelectLines(tw->term.tpd->termBuffer,
|
|
selectLineBegin, selectColBegin,
|
|
tw->term.tpd->lastUsedRow, selectInfo->columns);
|
|
} else {
|
|
(void) _DtTermPrimBufferSetSelectLines(tw->term.tpd->termBuffer,
|
|
selectLineBegin, selectColBegin,
|
|
selectLineEnd, selectColEnd);
|
|
}
|
|
Debug('c', fprintf(stderr, ">>setSelection() finishing b\n"));
|
|
}
|
|
|
|
|
|
static void
|
|
handleSelection
|
|
(
|
|
DtTermPrimitiveWidget tw,
|
|
int x,
|
|
int y,
|
|
Time selectTime
|
|
)
|
|
{
|
|
XmTextPosition position;
|
|
XmTextPosition newBegin;
|
|
XmTextPosition newEnd;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
|
|
Debug('c', fprintf(stderr, ">>handleSelection() starting\n"));
|
|
|
|
position = xyToPos(tw, x, y);
|
|
newBegin = scan(tw, position, selectInfo->scanType, scanLeft,
|
|
1, False);
|
|
newEnd = scan(tw, position, selectInfo->scanType, scanRight,
|
|
1, selectInfo->scanType == XmSELECT_LINE);
|
|
|
|
setSelection(tw, newBegin, newEnd, selectTime, False);
|
|
|
|
if ((position - newBegin) <
|
|
(newEnd - position))
|
|
{
|
|
selectInfo->extendDir = scanLeft;
|
|
}
|
|
else
|
|
{
|
|
selectInfo->extendDir = scanRight;
|
|
}
|
|
selectInfo->origBegin = newBegin;
|
|
selectInfo->origEnd = newEnd;
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* *
|
|
* browseScroll - timer proc that scrolls the list if the user has left *
|
|
* the window with the button down. If the button has been *
|
|
* released, call the standard click stuff. *
|
|
* *
|
|
************************************************************************/
|
|
/* ARGSUSED */
|
|
static void
|
|
browseScroll
|
|
(
|
|
XtPointer closure,
|
|
XtIntervalId *id
|
|
)
|
|
{
|
|
Widget w = (Widget) closure;
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo ;
|
|
XmScrollBarWidget vsb = (XmScrollBarWidget) tw->term.verticalScrollBar;
|
|
unsigned long interval;
|
|
|
|
if (selectInfo->cancel) {
|
|
selectInfo->selectID = 0;
|
|
return;
|
|
}
|
|
|
|
if (!selectInfo->selectID) return;
|
|
|
|
_DtTermPrimScrollComplete(w, True);
|
|
if ( selectInfo->isScrollUp ) {
|
|
if ( tpd->lastUsedRow-1 >= tpd->topRow + tw->term.rows)
|
|
_DtTermPrimScrollText(w, 1);
|
|
}
|
|
else
|
|
_DtTermPrimScrollText(w, -1);
|
|
_DtTermPrimScrollComplete(w, True);
|
|
if (selectInfo->extending)
|
|
doExtendedSelection(w, XtLastTimestampProcessed(XtDisplay(w)));
|
|
|
|
if (vsb)
|
|
interval = (unsigned long) vsb->scrollBar.repeat_delay;
|
|
else
|
|
interval = 100;
|
|
|
|
XSync (XtDisplay(w), False);
|
|
|
|
selectInfo->selectID = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
|
|
interval, browseScroll, (XtPointer) w);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static Boolean
|
|
CheckTimerScrolling
|
|
(
|
|
Widget w,
|
|
XEvent *event
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
XmScrollBarWidget vsb = (XmScrollBarWidget) tw->term.verticalScrollBar;
|
|
unsigned long interval;
|
|
|
|
selectInfo->extend.x = event->xmotion.x;
|
|
selectInfo->extend.y = event->xmotion.y;
|
|
|
|
if ( (event->xmotion.y > (int) tpd->offsetY) &&
|
|
(event->xmotion.y < (int) (tpd->offsetY + tw->term.rows *
|
|
tpd->cellHeight))) {
|
|
|
|
if (selectInfo->selectID) {
|
|
XtRemoveTimeOut(selectInfo->selectID);
|
|
selectInfo->selectID = 0;
|
|
}
|
|
} else {
|
|
/* above the text */
|
|
if (event->xmotion.y <= (int) tpd->offsetY) {
|
|
selectInfo->extend.x = 0;
|
|
selectInfo->extend.y = (int) (tpd->offsetY);
|
|
selectInfo->isScrollUp = False ;
|
|
|
|
/* below the text */
|
|
} else if (event->xmotion.y >= (int) (tpd->offsetY + tw->term.rows *
|
|
tpd->cellHeight)) {
|
|
selectInfo->extend.x = tw->core.width;
|
|
selectInfo->extend.y = (int) (tpd->offsetY + tw->term.rows *
|
|
tpd->cellHeight);
|
|
selectInfo->isScrollUp = True ;
|
|
}
|
|
|
|
if (vsb)
|
|
interval = (unsigned long) vsb->scrollBar.initial_delay;
|
|
else
|
|
interval = 200;
|
|
|
|
if (!selectInfo->selectID)
|
|
selectInfo->selectID = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
|
|
interval, browseScroll, (XtPointer) w);
|
|
return True;
|
|
}
|
|
return False;
|
|
}
|
|
|
|
/*
|
|
** Create and initialize the selection specific information
|
|
*/
|
|
TermSelectInfo
|
|
_DtTermPrimSelectCreate
|
|
(
|
|
Widget w
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo;
|
|
int i;
|
|
|
|
selectInfo = (TermSelectInfo)XtMalloc(sizeof(TermSelectInfoRec));
|
|
|
|
selectInfo->begin = 0;
|
|
selectInfo->end = 0;
|
|
selectInfo->columns = tw->term.columns;
|
|
selectInfo->rows = tpd->bufferRows + tpd->historyBufferRows;
|
|
selectInfo->direction = (TermScanDirection) XmTEXT_FORWARD;
|
|
selectInfo->extend.x = 0;
|
|
selectInfo->extend.y = 0;
|
|
selectInfo->extending = False;
|
|
selectInfo->hint.x = 0;
|
|
selectInfo->hint.y = 0;
|
|
selectInfo->lastTime = 0;
|
|
selectInfo->origBegin = 0;
|
|
selectInfo->origEnd = 0;
|
|
selectInfo->ownPrimary = False;
|
|
selectInfo->threshold = 5;
|
|
selectInfo->selectID = 0;
|
|
selectInfo->selectType = TermSelect_NORMAL;
|
|
selectInfo->scanType = defaultScanArray[0];
|
|
selectInfo->scanArraySize = XtNumber(defaultScanArray);
|
|
selectInfo->scanArray = (XmTextScanType *)
|
|
XtMalloc(selectInfo->scanArraySize *
|
|
sizeof(XmTextScanType));
|
|
selectInfo->cancel = True; /* used by scroll selection */
|
|
selectInfo->anchor = -1; /* in case extend happens before set*/
|
|
selectInfo->sel_start = False;
|
|
for (i = 0; i < selectInfo->scanArraySize; i++)
|
|
{
|
|
selectInfo->scanArray[i] = defaultScanArray[i];
|
|
}
|
|
|
|
RegisterDropSite(w);
|
|
return(selectInfo);
|
|
}
|
|
|
|
void
|
|
_DtTermPrimSelectInitBtnEvents(Widget w)
|
|
{
|
|
Boolean btn1_transfer = False;
|
|
XtVaGetValues((Widget)XmGetXmDisplay(XtDisplay(w)), "enableBtn1Transfer",
|
|
&btn1_transfer, NULL);
|
|
if (btn1_transfer)
|
|
XtOverrideTranslations(w,
|
|
XtParseTranslationTable(_DtTermEventBindingsCDE));
|
|
if (btn1_transfer == True) /* for btn2 extend case */
|
|
XtOverrideTranslations(w,
|
|
XtParseTranslationTable(_DtTermEventBindingsCDEBtn2));
|
|
}
|
|
|
|
void
|
|
_DtTermPrimSelectDisown
|
|
(
|
|
Widget w
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
|
|
if (selectInfo->ownPrimary == True)
|
|
{
|
|
XtDisownSelection(w, XA_PRIMARY, getServerTime(w));
|
|
selectInfo->ownPrimary = False ;
|
|
}
|
|
}
|
|
|
|
void
|
|
_DtTermPrimSelectDestroy
|
|
(
|
|
Widget w,
|
|
TermSelectInfo selectInfo
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (selectInfo->ownPrimary == True)
|
|
{
|
|
XtDisownSelection(w, XA_PRIMARY, getServerTime(w));
|
|
}
|
|
selectInfo->ownPrimary = False ;
|
|
XtFree((char *) selectInfo->scanArray);
|
|
XtFree((char *) selectInfo);
|
|
tpd->selectInfo = NULL ;
|
|
}
|
|
|
|
|
|
/*
|
|
** determine how much (if any) of the text is selected
|
|
**
|
|
** NOTE:
|
|
** beginCol + width will never exceed the width of the terminal
|
|
** buffer
|
|
*/
|
|
Boolean
|
|
_DtTermPrimSelectIsInSelection
|
|
(
|
|
Widget w,
|
|
int row,
|
|
short startCol,
|
|
short width,
|
|
short *selWidth
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
Boolean inSelection = True;
|
|
XmTextPosition endPosition;
|
|
XmTextPosition position;
|
|
XmTextPosition begin;
|
|
XmTextPosition end;
|
|
short beginRow, beginCol;
|
|
short endRow , endCol;
|
|
|
|
position = rowColToPos(tw, row, startCol);
|
|
endPosition = position + width;
|
|
|
|
begin = selectInfo->begin;
|
|
end = selectInfo->end;
|
|
|
|
if ((begin >= endPosition) || (end <= position))
|
|
{
|
|
/*
|
|
** outside of selection range...
|
|
*/
|
|
inSelection = False;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** we're in the selection range, clip endPosition as necessary...
|
|
*/
|
|
if (position < begin)
|
|
{
|
|
/*
|
|
** we start to the left of the selection...
|
|
*/
|
|
inSelection = False;
|
|
endPosition = MIN(endPosition, begin);
|
|
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** we must be in the selection, clip endPosition as
|
|
** necessary...
|
|
*/
|
|
endPosition = MIN(endPosition, end);
|
|
|
|
}
|
|
}
|
|
|
|
*selWidth = endPosition - position;
|
|
return(inSelection);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimSelectDoSelection
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectDoSelection() starting\n"));
|
|
|
|
handleSelection(tw, event->xbutton.x, event->xbutton.y,
|
|
event->xbutton.time);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimSelectSetHint
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
TermSelectInfo selectInfo =
|
|
((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
|
|
|
|
selectInfo->hint.x = event->xbutton.x;
|
|
selectInfo->hint.y = event->xbutton.y;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimSelectStart
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
XButtonEvent *btnEvent = (XButtonEvent *) event;
|
|
XmTextPosition begin;
|
|
XmTextPosition end;
|
|
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectStart() starting\n"));
|
|
|
|
/*
|
|
** set the selection hints, and scan type
|
|
*/
|
|
_DtTermPrimSelectSetHint(w, event, params, paramCount);
|
|
setScanType(w, event);
|
|
|
|
/*
|
|
** Set the current anchor point
|
|
*/
|
|
selectInfo->anchor = xyToPos(tw, btnEvent->x, btnEvent->y);
|
|
|
|
if (selectInfo->scanType != XmSELECT_POSITION ||
|
|
(_DtTermPrimSelectGetSelection(w, &begin, &end) && begin != end)
|
|
)
|
|
{
|
|
_DtTermPrimSelectDoSelection(w, event, params, paramCount);
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimSelectGrabFocus
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
XButtonEvent *btnEvent = (XButtonEvent *) event;
|
|
|
|
/* setDebugFlags("c") ; */
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectGrabFocus() starting\n"));
|
|
|
|
/* turn off the cursor */
|
|
_DtTermPrimCursorOff(w);
|
|
|
|
selectInfo->cancel = False;
|
|
tw->term.allowOsfKeysyms = True; /* normal dtterm doesn't honor these*/
|
|
/*
|
|
** constrain the button event to the terminal's text area
|
|
*/
|
|
if (btnEvent->x <= (int) tpd->offsetX)
|
|
{
|
|
/* left */
|
|
btnEvent->x = (int)(tpd->offsetX + 1);
|
|
} else if (btnEvent->x >= (int)(tw->core.width - tpd->offsetX))
|
|
{
|
|
/* right */
|
|
btnEvent->x = (int)(tw->core.width - tpd->offsetX - 1);
|
|
}
|
|
|
|
if (btnEvent->y <= (int)tpd->offsetY)
|
|
{
|
|
/* above */
|
|
btnEvent->y = (int)(tpd->offsetY + 1);
|
|
}
|
|
else if (btnEvent->y - ((int)(tpd->offsetY +
|
|
((tpd->lastUsedRow - tpd->topRow) *
|
|
tpd->cellHeight))) >= selectInfo->threshold)
|
|
{
|
|
/* below */
|
|
btnEvent->y = (int)(tpd->offsetY + ((tpd->lastUsedRow - tpd->topRow) *
|
|
tpd->cellHeight) - 1);
|
|
}
|
|
|
|
if (_XmGetFocusPolicy(w) == XmEXPLICIT)
|
|
(void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
|
|
|
|
_DtTermPrimSelectStart(w, event, params, paramCount);
|
|
}
|
|
|
|
|
|
static
|
|
Boolean
|
|
dragged
|
|
(
|
|
TermSelectionHint hint,
|
|
XEvent *event,
|
|
int threshold
|
|
)
|
|
{
|
|
return ((abs(hint.x - event->xbutton.x) > threshold) ||
|
|
(abs(hint.y - event->xbutton.y) > threshold));
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
doExtendedSelection
|
|
(
|
|
Widget w,
|
|
Time eventTime
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
XmTextPosition position;
|
|
XmTextPosition begin;
|
|
XmTextPosition end;
|
|
XmTextPosition cursorPos;
|
|
float midPoint;
|
|
|
|
if (selectInfo->cancel) {
|
|
if (selectInfo->selectID) XtRemoveTimeOut(selectInfo->selectID);
|
|
selectInfo->selectID = 0;
|
|
return;
|
|
}
|
|
|
|
position = xyToPos(tw, selectInfo->extend.x, selectInfo->extend.y);
|
|
|
|
if (!(_DtTermPrimSelectGetSelection(w, &begin, &end)) ||
|
|
(begin == end))
|
|
{
|
|
begin = position;
|
|
end = position;
|
|
if ( selectInfo->anchor <0) selectInfo->anchor = position;
|
|
selectInfo->origBegin = selectInfo->anchor;
|
|
selectInfo->origEnd = selectInfo->anchor;
|
|
midPoint = (float)selectInfo->anchor;
|
|
}
|
|
else
|
|
{
|
|
midPoint = (float)
|
|
(((float)(selectInfo->origEnd -
|
|
selectInfo->origBegin) / 2.0) +
|
|
(float)selectInfo->origBegin);
|
|
}
|
|
|
|
/*
|
|
** shift anchor and direction to opposite end of the selection
|
|
*/
|
|
if ((float)(position) <= midPoint)
|
|
{
|
|
selectInfo->anchor = selectInfo->origEnd;
|
|
if (!selectInfo->extending)
|
|
{
|
|
selectInfo->extendDir = scanLeft;
|
|
}
|
|
}
|
|
else if ((float)(position) > midPoint)
|
|
{
|
|
selectInfo->anchor = selectInfo->origBegin;
|
|
if (!selectInfo->extending)
|
|
{
|
|
selectInfo->extendDir = scanRight;
|
|
}
|
|
}
|
|
|
|
selectInfo->extending = TRUE;
|
|
|
|
/*
|
|
** check for change in extend direction
|
|
*/
|
|
if ((selectInfo->extendDir == scanRight &&
|
|
position < selectInfo->anchor) ||
|
|
(selectInfo->extendDir == scanLeft &&
|
|
position > selectInfo->anchor))
|
|
{
|
|
selectInfo->extendDir = (selectInfo->extendDir == scanRight) ?
|
|
scanLeft : scanRight;
|
|
|
|
begin = selectInfo->begin;
|
|
end = selectInfo->end;
|
|
}
|
|
|
|
|
|
if (selectInfo->extendDir == scanRight)
|
|
{
|
|
cursorPos = scan(tw, position, selectInfo->scanType, scanRight, 1,
|
|
selectInfo->scanType == XmSELECT_LINE);
|
|
end = cursorPos;
|
|
begin = selectInfo->anchor;
|
|
}
|
|
else
|
|
{
|
|
cursorPos = scan(tw, position, selectInfo->scanType, scanLeft, 1,
|
|
FALSE);
|
|
begin = cursorPos;
|
|
end = selectInfo->anchor;
|
|
if (selectInfo->scanType == XmSELECT_WORD &&
|
|
(int)tw->term.tpd->cellWidth > 1)
|
|
{
|
|
if (position == scan (tw, begin, selectInfo->scanType, scanRight, 1,
|
|
FALSE))
|
|
{
|
|
begin = position;
|
|
}
|
|
}
|
|
}
|
|
|
|
setSelection(tw, begin, end, eventTime, False);
|
|
}
|
|
|
|
void
|
|
_DtTermPrimSelectExtendStart(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *num_params )
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
|
|
selectInfo->cancel = False;
|
|
tw->term.allowOsfKeysyms = True ;
|
|
|
|
_DtTermPrimSelectExtend(w, event, params, num_params);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimSelectExtend
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectExtend() starting\n"));
|
|
|
|
/* turn off the cursor */
|
|
_DtTermPrimCursorOff(w);
|
|
|
|
if (_XmGetFocusPolicy(w) == XmEXPLICIT)
|
|
(void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
|
|
|
|
if (selectInfo->cancel) return ;
|
|
|
|
if ((selectInfo->hint.x > 0) || (selectInfo->hint.y > 0))
|
|
{
|
|
if (dragged(selectInfo->hint, event, selectInfo->threshold))
|
|
{
|
|
/*
|
|
** extend the selection
|
|
*/
|
|
handleSelection(tw,selectInfo->hint.x,selectInfo->hint.y,
|
|
event->xbutton.time);
|
|
selectInfo->hint.x = 0;
|
|
selectInfo->hint.y = 0;
|
|
selectInfo->extending = True;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** do nothing
|
|
*/
|
|
return;
|
|
}
|
|
}
|
|
/*
|
|
** check for timer scrolling here
|
|
** NOTE: CheckTimerScrolling(w,event) will set extend.[x|y]
|
|
* selectInfo->extend.x = event->xbutton.x;
|
|
* selectInfo->extend.y = event->xbutton.y;
|
|
*/
|
|
if (!CheckTimerScrolling(w,event) )
|
|
doExtendedSelection(w, event->xbutton.time);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimSelectExtendEnd
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectExtendEnd() starting\n"));
|
|
|
|
selectInfo->cancel = True; /* used by scroll selection */
|
|
tw->term.allowOsfKeysyms = False;
|
|
|
|
if (selectInfo->extending)
|
|
{
|
|
_DtTermPrimSelectGetSelection(w, &selectInfo->origBegin,
|
|
&selectInfo->origEnd);
|
|
setSelection(tw, selectInfo->origBegin, selectInfo->origEnd,
|
|
event->xbutton.time, False);
|
|
/* _DtTermPrimSelectExtend(w, event, params, paramCount);*/
|
|
}
|
|
|
|
if (selectInfo->selectID > 0)
|
|
{
|
|
XtRemoveTimeOut(selectInfo->selectID);
|
|
selectInfo->selectID = 0;
|
|
}
|
|
|
|
selectInfo->extend.x = 0;
|
|
selectInfo->extend.y = 0;
|
|
selectInfo->extending = False;
|
|
selectInfo->hint.x = 0;
|
|
selectInfo->hint.y = 0;
|
|
|
|
/* turn off the cursor */
|
|
_DtTermPrimCursorOn(w);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
doHandleTargets
|
|
(
|
|
Widget w,
|
|
XtPointer closure,
|
|
Atom *seltype,
|
|
Atom *type,
|
|
XtPointer value,
|
|
unsigned long *length,
|
|
int *format
|
|
)
|
|
{
|
|
_TermSelectPrimaryRec *primSelect = (_TermSelectPrimaryRec *) closure;
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
XTextProperty tmpProp;
|
|
XmTextBlockRec block;
|
|
int i, status;
|
|
char *pChar;
|
|
char *pCharEnd;
|
|
char *pCharFollow;
|
|
int malloc_size=0 , numVals ;
|
|
char *total_tmp_value ;
|
|
char **tmp_value ;
|
|
|
|
Debug('c', fprintf(stderr, ">>doHandleTargets() starting\n"));
|
|
|
|
if (_XmGetFocusPolicy(w) == XmEXPLICIT)
|
|
{
|
|
(void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
|
|
}
|
|
|
|
if (*type == XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False) ||
|
|
*type == XA_STRING)
|
|
{
|
|
|
|
tmpProp.value = (unsigned char *) value;
|
|
tmpProp.encoding = *type;
|
|
tmpProp.format = *format;
|
|
tmpProp.nitems = *length;
|
|
numVals = 0;
|
|
status = XmbTextPropertyToTextList(XtDisplay(w), &tmpProp,
|
|
&tmp_value, &numVals );
|
|
|
|
/*
|
|
** if no conversions, numVals doesn't change
|
|
*/
|
|
if (numVals && (status == Success || status > 0))
|
|
{
|
|
for (i = 0; i < numVals ; i++)
|
|
{
|
|
malloc_size += strlen(tmp_value[i]);
|
|
}
|
|
total_tmp_value = XtMalloc ((unsigned) malloc_size + 1);
|
|
total_tmp_value[0] = '\0';
|
|
for (i = 0; i < numVals ; i++)
|
|
{
|
|
strcat(total_tmp_value, tmp_value[i]);
|
|
}
|
|
block.ptr = total_tmp_value;
|
|
block.length = strlen(total_tmp_value);
|
|
block.format = XmFMT_8_BIT;
|
|
XFreeStringList(tmp_value);
|
|
}
|
|
else
|
|
{
|
|
malloc_size = 1; /* to force space to be freed */
|
|
total_tmp_value = XtMalloc ((unsigned)1);
|
|
*total_tmp_value = '\0';
|
|
block.ptr = total_tmp_value;
|
|
block.length = 0;
|
|
block.format = XmFMT_8_BIT;
|
|
}
|
|
} else {
|
|
|
|
block.ptr = (char*)value;
|
|
block.length = (int) *length; /* NOTE: this causes a truncation on
|
|
some architectures */
|
|
block.format = XmFMT_8_BIT;
|
|
}
|
|
|
|
pCharEnd = block.ptr + block.length;
|
|
pCharFollow = (char *)block.ptr;
|
|
|
|
for (pChar = (char *)block.ptr; pChar < pCharEnd; pChar++)
|
|
{
|
|
if (*pChar == '\n')
|
|
{
|
|
*pChar = '\r';
|
|
DtTermSubprocSend(w, (unsigned char *) pCharFollow,
|
|
pChar - pCharFollow + 1);
|
|
pCharFollow = pChar + 1;
|
|
}
|
|
}
|
|
if (pCharFollow < pCharEnd)
|
|
{
|
|
DtTermSubprocSend(w, (unsigned char *) pCharFollow,
|
|
pCharEnd - pCharFollow);
|
|
}
|
|
|
|
if (malloc_size != 0) XtFree(total_tmp_value);
|
|
XtFree((char *)value);
|
|
if (primSelect && (--primSelect->ref_count == 0))
|
|
{
|
|
XtFree((char *)primSelect);
|
|
}
|
|
value = NULL ;
|
|
}
|
|
|
|
/*
|
|
** Look at the target list and determine what target to place in the
|
|
** pair. it will then do any necessary conversions before "thrusting"
|
|
** the selection value onto the receiver. this will guarantee the
|
|
** best chance at a successful exchange.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
handleTargets
|
|
(
|
|
Widget w,
|
|
XtPointer closure,
|
|
Atom *selType,
|
|
Atom *type,
|
|
XtPointer value,
|
|
unsigned long *length,
|
|
int *format
|
|
)
|
|
{
|
|
Atom CS_OF_LOCALE;
|
|
Atom COMPOUND_TEXT;
|
|
Boolean supportsLocaleData;
|
|
Boolean supportsCompoundText;
|
|
Atom *atomPtr;
|
|
_TermSelectRec *tmpAction;
|
|
_TermSelectPrimaryRec *primSelect;
|
|
char *abcString;
|
|
XTextProperty tmpProp;
|
|
int status;
|
|
XtPointer closures[2];
|
|
Atom targets[2];
|
|
int i;
|
|
|
|
/*
|
|
** make sure we have something to do...
|
|
*/
|
|
tmpAction = (_TermSelectRec *) closure;
|
|
if (!length || *length == 0) {
|
|
XtFree((char *)value);
|
|
value = NULL;
|
|
XtFree((char *)tmpAction->event);
|
|
XtFree((char *)tmpAction);
|
|
return;
|
|
}
|
|
|
|
COMPOUND_TEXT = XmInternAtom(XtDisplay(w),"COMPOUND_TEXT", False);
|
|
supportsLocaleData = False;
|
|
supportsCompoundText = False;
|
|
abcString = "ABC"; /* characters in XPCS, so... safe */
|
|
atomPtr = (Atom *)value;
|
|
|
|
tmpProp.value = NULL;
|
|
status = XmbTextListToTextProperty(XtDisplay(w), &abcString, 1,
|
|
(XICCEncodingStyle)XTextStyle, &tmpProp);
|
|
if (status == Success)
|
|
{
|
|
CS_OF_LOCALE = tmpProp.encoding;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** Kludge for failure of XmbText... to
|
|
** handle XPCS characters. Should never
|
|
** happen, but this prevents a core dump
|
|
** if X11 is broken.
|
|
*/
|
|
CS_OF_LOCALE = (Atom)9999;
|
|
}
|
|
if (tmpProp.value != NULL)
|
|
{
|
|
XFree((char *)tmpProp.value);
|
|
}
|
|
|
|
for (i = 0; i < *length; i++, atomPtr++)
|
|
{
|
|
if (*atomPtr == CS_OF_LOCALE)
|
|
{
|
|
supportsLocaleData = True;
|
|
break;
|
|
}
|
|
if (*atomPtr == COMPOUND_TEXT)
|
|
{
|
|
supportsCompoundText = True;
|
|
}
|
|
}
|
|
primSelect = (_TermSelectPrimaryRec *)
|
|
XtMalloc((unsigned) sizeof(_TermSelectPrimaryRec));
|
|
|
|
/*
|
|
** If owner and I are using the same codeset, ask for it. If not,
|
|
** and if the owner supports compound text, ask for compound text.
|
|
** If not, fall back position is to ask for STRING and try to
|
|
** convert it locally.
|
|
*/
|
|
if (supportsLocaleData)
|
|
{
|
|
primSelect->target = targets[0] = CS_OF_LOCALE;
|
|
}
|
|
else if (supportsCompoundText)
|
|
{
|
|
primSelect->target = targets[0] = COMPOUND_TEXT;
|
|
}
|
|
else
|
|
{
|
|
primSelect->target = targets[0] = XA_STRING;
|
|
}
|
|
closures[0] = (char *)primSelect;
|
|
|
|
primSelect->ref_count = 1;
|
|
/*
|
|
** Make request to call doHandleTargets() with the primary selection.
|
|
*/
|
|
XtGetSelectionValue(w, XA_PRIMARY, targets[0], doHandleTargets,
|
|
(XtPointer)primSelect,
|
|
tmpAction->event->xbutton.time);
|
|
|
|
XtFree((char *)value);
|
|
value = NULL;
|
|
XtFree((char *)tmpAction->event);
|
|
XtFree((char *)tmpAction);
|
|
}
|
|
|
|
static char *
|
|
getString
|
|
(
|
|
Widget w,
|
|
XmTextPosition begin,
|
|
XmTextPosition end,
|
|
Boolean needWideChar
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
TermBuffer tb;
|
|
short beginRow,
|
|
beginCol;
|
|
short endRow,
|
|
endCol;
|
|
short thisRow;
|
|
short numRows;
|
|
char *buffer;
|
|
char *pBuf;
|
|
short len;
|
|
|
|
beginRow = begin / (selectInfo->columns + 1);
|
|
beginCol = begin - (beginRow * (selectInfo->columns + 1));
|
|
endRow = end / (selectInfo->columns + 1);
|
|
endCol = end - (endRow * (selectInfo->columns + 1));
|
|
numRows = endRow - beginRow + 1;
|
|
|
|
/*
|
|
** we need to store end - begin characters, a terminating byte, plus
|
|
** a new line for each line...
|
|
**
|
|
** NOTE: end - begin could result in a truncated long.
|
|
*/
|
|
buffer = XtMalloc(((int)(end - begin) + 1 + numRows) * sizeof(char)
|
|
* BYTES_PER_CHAR(tpd->termBuffer));
|
|
|
|
/*
|
|
** return a null string if there is nothing to do
|
|
*/
|
|
if (begin == end)
|
|
{
|
|
*buffer = 0x00;
|
|
return(buffer);
|
|
}
|
|
|
|
/*
|
|
** Accomodate the history buffer as necessary
|
|
*/
|
|
if (tpd->useHistoryBuffer)
|
|
{
|
|
beginRow -= tpd->lastUsedHistoryRow;
|
|
endRow -= tpd->lastUsedHistoryRow;
|
|
}
|
|
|
|
/*
|
|
** get the first (and possibly only) line of text
|
|
*/
|
|
pBuf = buffer;
|
|
if (beginRow == endRow)
|
|
{
|
|
if (beginRow < 0)
|
|
{
|
|
tb = tpd->historyBuffer;
|
|
thisRow = beginRow + tpd->lastUsedHistoryRow;
|
|
}
|
|
else
|
|
{
|
|
tb = tpd->termBuffer;
|
|
thisRow = beginRow;
|
|
}
|
|
len = _DtTermPrimBufferGetText(tb, thisRow, beginCol,
|
|
endCol - beginCol, pBuf, needWideChar);
|
|
pBuf += len;
|
|
}
|
|
else
|
|
{
|
|
if (beginRow < 0)
|
|
{
|
|
tb = tpd->historyBuffer;
|
|
thisRow = beginRow + tpd->lastUsedHistoryRow;
|
|
}
|
|
else
|
|
{
|
|
tb = tpd->termBuffer;
|
|
thisRow = beginRow;
|
|
}
|
|
len = _DtTermPrimBufferGetText(tb, thisRow, beginCol,
|
|
selectInfo->columns - beginCol, pBuf,
|
|
needWideChar);
|
|
pBuf += len;
|
|
|
|
if ( !_DtTermPrimBufferTestLineWrapFlag(tb,thisRow) ) {
|
|
*pBuf = '\n'; /* newline */
|
|
pBuf++;
|
|
}
|
|
|
|
/*
|
|
** get the middle block (if there is one)
|
|
*/
|
|
beginRow++;
|
|
while(beginRow < endRow)
|
|
{
|
|
if (beginRow < 0)
|
|
{
|
|
tb = tpd->historyBuffer;
|
|
thisRow = beginRow + tpd->lastUsedHistoryRow;
|
|
}
|
|
else
|
|
{
|
|
tb = tpd->termBuffer;
|
|
thisRow = beginRow;
|
|
}
|
|
len = _DtTermPrimBufferGetText(tb, thisRow, 0,
|
|
selectInfo->columns , pBuf,
|
|
needWideChar);
|
|
|
|
pBuf += len;
|
|
/* if (len != 0 && len < selectInfo->columns ) { */
|
|
if ( !_DtTermPrimBufferTestLineWrapFlag(tb,thisRow) ) {
|
|
*pBuf = '\n'; /* newline */
|
|
pBuf++;
|
|
}
|
|
beginRow++;
|
|
}
|
|
|
|
/*
|
|
** get the last line
|
|
*/
|
|
if (endRow < 0)
|
|
{
|
|
tb = tpd->historyBuffer;
|
|
thisRow = endRow + tpd->lastUsedHistoryRow;
|
|
}
|
|
else
|
|
{
|
|
tb = tpd->termBuffer;
|
|
thisRow = endRow;
|
|
}
|
|
len = _DtTermPrimBufferGetText(tb, thisRow, 0, endCol, pBuf,
|
|
needWideChar);
|
|
pBuf += len;
|
|
}
|
|
*pBuf = 0x00;
|
|
|
|
return(buffer);
|
|
}
|
|
|
|
/*
|
|
** Request targets from selection owner.
|
|
*/
|
|
static void
|
|
getTargets
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
_TermSelectRec *tmp;
|
|
|
|
tmp = (_TermSelectRec*)XtMalloc(sizeof(_TermSelectRec));
|
|
|
|
/*
|
|
** Request targets from the selection owner so you can decide what to
|
|
** request. The decision process and request for the selection is
|
|
** taken care of in handleTargets().
|
|
*/
|
|
|
|
tmp->event = (XEvent *) XtMalloc(sizeof(XEvent));
|
|
memcpy((void *)tmp->event, (void *)event, sizeof(XEvent));
|
|
|
|
tmp->params = params;
|
|
tmp->num_params = paramCount;
|
|
|
|
XtGetSelectionValue(w, XA_PRIMARY,
|
|
XmInternAtom(XtDisplay(w), "TARGETS", False),
|
|
handleTargets, (XtPointer)tmp, event->xbutton.time);
|
|
}
|
|
|
|
Boolean
|
|
_DtTermPrimSelectConvert
|
|
(
|
|
Widget w,
|
|
Atom *selection,
|
|
Atom *target,
|
|
Atom *type,
|
|
XtPointer *value,
|
|
unsigned long *length,
|
|
int *format
|
|
)
|
|
{
|
|
Atom TARGETS = XmInternAtom(XtDisplay(w), "TARGETS", False);
|
|
Atom CS_OF_LOCALE;
|
|
Atom COMPOUND_TEXT = XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False);
|
|
Atom TEXT = XmInternAtom(XtDisplay(w), "TEXT", False);
|
|
Atom MOTIF_DROP = XmInternAtom(XtDisplay(w), "_MOTIF_DROP", False);
|
|
int maxTargets = 10;
|
|
int targetCount;
|
|
int status;
|
|
Widget widget;
|
|
Boolean ownPrimary;
|
|
XmTextPosition begin;
|
|
XmTextPosition end;
|
|
char *tmpValue;
|
|
char *tmpString = "ABC"; /* characters in XPCS, so... safe */
|
|
XTextProperty tmpProp;
|
|
XtPointer c_ptr;
|
|
Arg args[1];
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectConvert() starting\n"));
|
|
|
|
if (*selection == MOTIF_DROP) {
|
|
XtSetArg(args[0], XmNclientData, &c_ptr);
|
|
XtGetValues(w, args, 1);
|
|
widget = (Widget)c_ptr;
|
|
} else
|
|
widget = w;
|
|
|
|
if (widget == NULL) return False;
|
|
|
|
tmpProp.value = NULL;
|
|
status = XmbTextListToTextProperty(XtDisplay(widget), &tmpString, 1,
|
|
(XICCEncodingStyle)XTextStyle, &tmpProp);
|
|
if (status == Success)
|
|
{
|
|
CS_OF_LOCALE = tmpProp.encoding;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** XmbTextList... SHOULD never fail for
|
|
** XPCS character. But if it does, this
|
|
** prevents a core dump.
|
|
*/
|
|
CS_OF_LOCALE = (Atom) 9999;
|
|
}
|
|
|
|
if (tmpProp.value != NULL)
|
|
XFree((char *) tmpProp.value);
|
|
|
|
|
|
if (*selection == XA_PRIMARY || *selection == MOTIF_DROP)
|
|
{
|
|
ownPrimary = _DtTermPrimSelectGetSelection(widget, &begin, &end);
|
|
}
|
|
else
|
|
{
|
|
return(False);
|
|
}
|
|
|
|
if (*target == TARGETS)
|
|
{
|
|
Atom *targets = (Atom *)XtMalloc((unsigned)(maxTargets * sizeof(Atom)));
|
|
|
|
/*
|
|
** Xt should take care of TIME_STAMP for us.
|
|
*/
|
|
targetCount = 0;
|
|
*value = (XtPointer)targets;
|
|
*targets++ = TARGETS; targetCount++;
|
|
if (!isDebugFSet('s', 1)) {
|
|
*targets++ = COMPOUND_TEXT; targetCount++;
|
|
}
|
|
if (!isDebugFSet('s', 2)) {
|
|
*targets++ = CS_OF_LOCALE; targetCount++;
|
|
}
|
|
if (!isDebugFSet('s', 3)) {
|
|
*targets++ = TEXT; targetCount++;
|
|
}
|
|
if (!isDebugFSet('s', 4)) {
|
|
*targets++ = XA_STRING; targetCount++;
|
|
}
|
|
*type = XA_ATOM;
|
|
*length = (targetCount * sizeof(Atom)) >> 2; /* convert to work count */
|
|
*format = 32;
|
|
}
|
|
else if (!ownPrimary)
|
|
{
|
|
return(False);
|
|
}
|
|
else if ((*target == XA_STRING && !isDebugFSet('s', 4)) ||
|
|
(*target == COMPOUND_TEXT && !isDebugFSet('s', 1)))
|
|
{
|
|
tmpValue = getString(widget, begin, end, False);
|
|
tmpProp.value = NULL;
|
|
if ((*target == XA_STRING) && !isDebugFSet('s', 4)) {
|
|
*type = (Atom) XA_STRING;
|
|
*format = 8;
|
|
status = XmbTextListToTextProperty(XtDisplay(widget), &tmpValue, 1,
|
|
(XICCEncodingStyle)XStringStyle,
|
|
&tmpProp);
|
|
}
|
|
else if ((*target == COMPOUND_TEXT) && !isDebugFSet('s',1)) {
|
|
*type = COMPOUND_TEXT;
|
|
*format = 8;
|
|
status = XmbTextListToTextProperty(XtDisplay(widget), &tmpValue, 1,
|
|
(XICCEncodingStyle)XCompoundTextStyle,
|
|
&tmpProp);
|
|
}
|
|
XtFree(tmpValue);
|
|
if (status == Success || status > 0)
|
|
{
|
|
/*
|
|
** NOTE: casting tmpProp.nitems could result in a truncated long.
|
|
*/
|
|
if (tmpProp.nitems > 0)
|
|
*value = (XtPointer) XtMalloc((unsigned)tmpProp.nitems);
|
|
else
|
|
*value = (XtPointer) XtMalloc(1);
|
|
|
|
*length = tmpProp.nitems;
|
|
memcpy((void*)*value, (void*)tmpProp.value,
|
|
(unsigned)tmpProp.nitems);
|
|
if (tmpProp.value != NULL)
|
|
XFree((char*)tmpProp.value);
|
|
}
|
|
else
|
|
{
|
|
*value = NULL;
|
|
*length = 0;
|
|
if (tmpProp.value != NULL)
|
|
XFree((char*)tmpProp.value);
|
|
return(False);
|
|
}
|
|
}
|
|
else if (((*target == CS_OF_LOCALE) && !isDebugFSet('s', 2)) ||
|
|
(*target == TEXT && !isDebugFSet('s', 3)))
|
|
{
|
|
*type = CS_OF_LOCALE;
|
|
*format = 8;
|
|
*value = (XtPointer)getString(widget, begin, end, False);
|
|
*length = strlen((char*) *value);
|
|
}
|
|
else
|
|
{
|
|
*value = NULL;
|
|
*length = 0;
|
|
return(False);
|
|
}
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectConvert() exiting\n"));
|
|
return(True);
|
|
}
|
|
|
|
void
|
|
_DtTermPrimSelectLoseSelection
|
|
(
|
|
Widget w,
|
|
Atom *selection
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
Boolean restoreCursor = False;
|
|
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectLoseSelection() starting\n"));
|
|
|
|
if (*selection == XA_PRIMARY && selectInfo->ownPrimary)
|
|
{
|
|
|
|
/*
|
|
** We've lost the primary selection, make a dummy call to
|
|
** setSelection (with begin > end) to clear things up...
|
|
*/
|
|
/* turn off the cursor */
|
|
if (tw->term.tpd->cursorState != CURSORoff) {
|
|
_DtTermPrimCursorOff(w);
|
|
restoreCursor = True;
|
|
}
|
|
|
|
setSelection(tw, 1, -99, XtLastTimestampProcessed(XtDisplay(w)), True);
|
|
|
|
/* turn on the cursor */
|
|
if (restoreCursor) {
|
|
_DtTermPrimCursorOn(w);
|
|
}
|
|
}
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectLoseSelection() exiting\n"));
|
|
}
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimSelectBDragRelease
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
TermSelectInfo selectInfo =
|
|
((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
|
|
XButtonEvent *btnEvent = (XButtonEvent *) event;
|
|
|
|
Debug('c', fprintf(stderr, ">>_DtTermPrimSelectBDragRelease() starting\n"));
|
|
|
|
/* Work around for intrinsic bug. Remove once bug is fixed.
|
|
** this is for drag/drop
|
|
*/
|
|
XtUngrabPointer(w, btnEvent->time);
|
|
|
|
if ( selectInfo->sel_start ) getTargets(w, event, params, paramCount);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
_DtTermPrimSelectInsert
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
|
|
if (!selectInfo->cancel)
|
|
_DtTermPrimSelectBDragRelease(w, event, params, paramCount);
|
|
|
|
selectInfo->cancel = True ;
|
|
|
|
/* turn on the cursor */
|
|
_DtTermPrimCursorOn(w);
|
|
}
|
|
|
|
Boolean
|
|
_DtTermPrimSelectIsAboveSelection
|
|
(
|
|
Widget w,
|
|
short row,
|
|
short col
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
XmTextPosition curPos, endPos;
|
|
|
|
endPos = selectInfo->end ;
|
|
curPos = rowColToPos(tw,row,col) ;
|
|
|
|
if ( curPos < endPos )
|
|
return(True) ;
|
|
else
|
|
return(False) ;
|
|
}
|
|
|
|
void
|
|
_DtTermPrimSelectResize
|
|
(
|
|
Widget w
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
|
|
_DtTermPrimSelectDisown(w) ;
|
|
selectInfo->columns = tw->term.columns ;
|
|
}
|
|
|
|
extern void
|
|
_DtTermPrimSelectMoveLines
|
|
(
|
|
Widget w,
|
|
short src,
|
|
short dest,
|
|
short len
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
short selectLineBegin;
|
|
short selectLineEnd;
|
|
TermBuffer pb;
|
|
short row,col;
|
|
|
|
posToBufferRowCol (tw, selectInfo->begin, &pb, &row, &col);
|
|
|
|
/* if there are no lines, etc. return... */
|
|
if ((len <= 0) || (src == dest) || !selectInfo->ownPrimary ||
|
|
pb == tw->term.tpd->historyBuffer ) {
|
|
return;
|
|
}
|
|
if (row >= src && row < (src + len)) {
|
|
selectInfo->begin -= (src - dest) * (selectInfo->columns + 1);
|
|
selectInfo->end -= (src - dest) * (selectInfo->columns + 1);
|
|
}
|
|
}
|
|
|
|
extern void
|
|
_DtTermPrimSelectDeleteLines
|
|
(
|
|
Widget w,
|
|
short src,
|
|
short len
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
short selectLineBegin;
|
|
short selectLineEnd;
|
|
TermBuffer pb;
|
|
short row,col;
|
|
|
|
posToBufferRowCol (tw, selectInfo->begin, &pb, &row, &col);
|
|
|
|
/* if there are no lines, etc. return... */
|
|
if ((len <= 0) || !selectInfo->ownPrimary ||
|
|
((tw->term.tpd->scrollLockTopRow > 0 ||
|
|
(tw->term.tpd->scrollLockBottomRow < tw->term.rows-1)) &&
|
|
row < tw->term.tpd->scrollLockTopRow)) {
|
|
|
|
return;
|
|
}
|
|
|
|
/* figure out what the begin line is... */
|
|
selectLineBegin = selectInfo->begin / (selectInfo->columns + 1);
|
|
|
|
/* if the beginning of the selection is after the source, we need to
|
|
* move the selection up...
|
|
*/
|
|
if (selectLineBegin > src) {
|
|
selectInfo->begin -= len * (selectInfo->columns + 1);
|
|
selectInfo->end -= len * (selectInfo->columns + 1);
|
|
if (selectInfo->begin < 0) {
|
|
(void) _DtTermPrimSelectDisown(w);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern void
|
|
_DtTermPrimSelectInsertLines
|
|
(
|
|
Widget w,
|
|
short src,
|
|
short len
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
short selectLineBegin;
|
|
short selectLineEnd;
|
|
|
|
/* if there are no lines, return... */
|
|
if ((len <= 0) || !selectInfo->ownPrimary) {
|
|
return;
|
|
}
|
|
|
|
/* figure out what the begin line is... */
|
|
selectLineBegin = selectInfo->begin / (selectInfo->columns + 1);
|
|
|
|
/* if the beginning of the selection is at or after the source, we need to
|
|
* move the selection up...
|
|
*/
|
|
if (selectLineBegin >= src) {
|
|
selectInfo->begin += len * (selectInfo->columns + 1);
|
|
selectInfo->end += len * (selectInfo->columns + 1);
|
|
}
|
|
}
|
|
|
|
void
|
|
_DtTermPrimSelectAll
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermSelectInfo selectInfo = tpd->selectInfo;
|
|
XButtonEvent *btnEvent = (XButtonEvent *) event;
|
|
XmTextPosition begin;
|
|
XmTextPosition end;
|
|
|
|
/* position not used in XmSELECT_ALL case */
|
|
begin = scan(tw, (XmTextPosition) 0, XmSELECT_ALL, scanLeft,
|
|
1, False);
|
|
end = scan(tw, (XmTextPosition) 0, XmSELECT_ALL, scanRight,
|
|
1, selectInfo->scanType == XmSELECT_LINE);
|
|
|
|
/* turn off the cursor */
|
|
_DtTermPrimCursorOff(w);
|
|
|
|
setSelection(tw, begin, end, event->xbutton.time, False);
|
|
|
|
/* turn on the cursor */
|
|
_DtTermPrimCursorOn(w);
|
|
}
|
|
|
|
void
|
|
_DtTermPrimSelectPage
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *paramCount
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
XButtonEvent *btnEvent = (XButtonEvent *) event;
|
|
XmTextPosition begin, end;
|
|
short lastRow, width;
|
|
TermBuffer pb;
|
|
|
|
begin = xyToPos(tw, 1, 1);
|
|
end = xyToPos(tw, tw->core.width-1, tw->core.height-1);
|
|
|
|
/* turn off the cursor */
|
|
_DtTermPrimCursorOff(w);
|
|
|
|
setSelection(tw, begin, end, event->xbutton.time, False);
|
|
|
|
/* turn on the cursor */
|
|
_DtTermPrimCursorOn(w);
|
|
}
|
|
|
|
/*
|
|
* DROP SITE code
|
|
*/
|
|
|
|
static XContext _DtTermDNDContext = 0;
|
|
|
|
static void
|
|
DropTransferCallback(
|
|
Widget w,
|
|
XtPointer closure,
|
|
Atom *seltype,
|
|
Atom *type,
|
|
XtPointer value,
|
|
unsigned long *length,
|
|
int *format )
|
|
{
|
|
_DtTermDropTransferRec *transfer_rec = (_DtTermDropTransferRec *) closure;
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)transfer_rec->widget;
|
|
|
|
/* When type = NULL, we are assuming a DELETE request has been requested */
|
|
if (*type == 0) {
|
|
if (value) {
|
|
XtFree((char *)value);
|
|
value = NULL;
|
|
}
|
|
return;
|
|
}
|
|
doHandleTargets((Widget)tw,NULL,seltype,type,value,length,format) ;
|
|
if (transfer_rec->move) {
|
|
XmDropTransferEntryRec transferEntries[1];
|
|
XmDropTransferEntryRec *transferList = NULL;
|
|
|
|
transferEntries[0].client_data = (XtPointer) transfer_rec;
|
|
transferEntries[0].target = XmInternAtom(XtDisplay(w),"DELETE",
|
|
False);
|
|
XmDropTransferAdd(w, transferEntries, 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
DeleteDropContext(
|
|
Widget w )
|
|
{
|
|
Display *display = XtDisplay(w);
|
|
Screen *screen = XtScreen(w);
|
|
|
|
XDeleteContext(display, (Window)screen, _DtTermDNDContext);
|
|
}
|
|
|
|
static void
|
|
SetDropContext(
|
|
Widget w )
|
|
{
|
|
Display *display = XtDisplay(w);
|
|
Screen *screen = XtScreen(w);
|
|
|
|
_DtTermProcessLock();
|
|
if (_DtTermDNDContext == 0)
|
|
_DtTermDNDContext = XUniqueContext();
|
|
_DtTermProcessUnlock();
|
|
|
|
XSaveContext(display, (Window)screen,
|
|
_DtTermDNDContext, (XPointer)w);
|
|
}
|
|
|
|
typedef struct _dropDestroyCBClientData {
|
|
_DtTermDropTransferRec *transfer_rec;
|
|
XtCallbackRec *dropDestroyCB; }
|
|
dropDestroyCBClientData;
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
DropDestroyCB(
|
|
Widget w,
|
|
XtPointer clientData,
|
|
XtPointer callData )
|
|
{
|
|
dropDestroyCBClientData *ptr = (dropDestroyCBClientData *) clientData;
|
|
|
|
DeleteDropContext(w);
|
|
|
|
if (ptr) {
|
|
if (ptr->transfer_rec) XtFree((char *) ptr->transfer_rec);
|
|
if (ptr->dropDestroyCB) XtFree((char *) ptr->dropDestroyCB);
|
|
XtFree((char *) ptr);
|
|
}
|
|
}
|
|
|
|
static void
|
|
HandleDrop( Widget w, XmDropProcCallbackStruct *cb )
|
|
{
|
|
Widget drag_cont, initiator;
|
|
/* XmTextWidget tw = (XmTextWidget) w; */
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
Cardinal numExportTargets, n;
|
|
Atom *exportTargets;
|
|
Arg args[10];
|
|
XmTextPosition insert_pos, left, right;
|
|
XtCallbackRec *dropDestroyCB, *dd_cb;
|
|
dropDestroyCBClientData *clientData;
|
|
|
|
clientData = (dropDestroyCBClientData *) XtMalloc(sizeof(dropDestroyCBClientData));
|
|
dropDestroyCB = dd_cb = (XtCallbackRec *) XtMalloc(2 * sizeof (XtCallbackRec));
|
|
|
|
clientData->dropDestroyCB = dropDestroyCB;
|
|
dd_cb->callback = DropDestroyCB;
|
|
dd_cb->closure = NULL;
|
|
dd_cb++;
|
|
dd_cb->callback = (XtCallbackProc) NULL;
|
|
dd_cb->closure = NULL;
|
|
|
|
drag_cont = cb->dragContext;
|
|
|
|
n = 0;
|
|
XtSetArg(args[n], XmNsourceWidget, &initiator); n++;
|
|
XtSetArg(args[n], XmNexportTargets, &exportTargets); n++;
|
|
XtSetArg(args[n], XmNnumExportTargets, &numExportTargets); n++;
|
|
XtGetValues((Widget) drag_cont, args, n);
|
|
|
|
{
|
|
XmDropTransferEntryRec transferEntries[2];
|
|
XmDropTransferEntryRec *transferList = NULL;
|
|
Atom TEXT = XmInternAtom(XtDisplay(w), "TEXT", False);
|
|
Atom COMPOUND_TEXT = XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False);
|
|
Atom CS_OF_LOCALE;
|
|
char * tmp_string = "ABC"; /* these are characters in XPCS, so... safe */
|
|
XTextProperty tmp_prop;
|
|
_DtTermDropTransferRec *transfer_rec;
|
|
Cardinal numTransfers = 0;
|
|
Boolean locale_found = False;
|
|
Boolean c_text_found = False;
|
|
Boolean string_found = False;
|
|
Boolean text_found = False;
|
|
int status;
|
|
|
|
tmp_prop.value = NULL;
|
|
|
|
status = XmbTextListToTextProperty(XtDisplay(w), &tmp_string, 1,
|
|
(XICCEncodingStyle)XTextStyle, &tmp_prop);
|
|
if (status == Success)
|
|
CS_OF_LOCALE = tmp_prop.encoding;
|
|
else
|
|
CS_OF_LOCALE = 99999; /* XmbTextList... should never fail for XPCS
|
|
* characters. But just in case someones
|
|
* Xlib is broken, this prevents a core dump.
|
|
*/
|
|
|
|
if (tmp_prop.value != NULL) XFree((char *)tmp_prop.value);
|
|
|
|
/* intialize data to send to drop transfer callback */
|
|
transfer_rec = (_DtTermDropTransferRec *)
|
|
XtMalloc(sizeof(_DtTermDropTransferRec));
|
|
clientData->transfer_rec = transfer_rec;
|
|
transfer_rec->widget = w;
|
|
/* don't actually need all of this for dtterm - it was from Text widget
|
|
*transfer_rec->insert_pos = insert_pos;
|
|
*transfer_rec->num_chars = 0;
|
|
*transfer_rec->timestamp = cb->timeStamp;
|
|
*
|
|
*/
|
|
|
|
if (cb->operation & XmDROP_MOVE) {
|
|
transfer_rec->move = True;
|
|
} else {
|
|
transfer_rec->move = False;
|
|
}
|
|
|
|
transferEntries[0].client_data = (XtPointer) transfer_rec;
|
|
transferList = transferEntries;
|
|
numTransfers = 1;
|
|
|
|
for (n = 0; n < numExportTargets; n++) {
|
|
if (exportTargets[n] == CS_OF_LOCALE) {
|
|
transferEntries[0].target = CS_OF_LOCALE;
|
|
locale_found = True;
|
|
break;
|
|
}
|
|
if (exportTargets[n] == COMPOUND_TEXT) c_text_found = True;
|
|
if (exportTargets[n] == XA_STRING) string_found = True;
|
|
if (exportTargets[n] == TEXT) text_found = True;
|
|
}
|
|
|
|
n = 0;
|
|
if (locale_found || c_text_found || string_found || text_found) {
|
|
if (!locale_found) {
|
|
if (c_text_found)
|
|
transferEntries[0].target = COMPOUND_TEXT;
|
|
else if (string_found)
|
|
transferEntries[0].target = XA_STRING;
|
|
else
|
|
transferEntries[0].target = TEXT;
|
|
}
|
|
|
|
if ( cb->operation & (XmDROP_COPY|XmDROP_MOVE) ) {
|
|
XtSetArg(args[n], XmNdropTransfers, transferList); n++;
|
|
XtSetArg(args[n], XmNnumDropTransfers, numTransfers); n++;
|
|
} else {
|
|
XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
|
|
XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
|
|
}
|
|
} else {
|
|
XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
|
|
XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
|
|
}
|
|
dropDestroyCB->closure = (XtPointer) clientData;
|
|
XtSetArg(args[n], XmNdestroyCallback, dropDestroyCB); n++;
|
|
XtSetArg(args[n], XmNtransferProc, DropTransferCallback); n++;
|
|
}
|
|
SetDropContext(w);
|
|
XmDropTransferStart(drag_cont, args, n);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
DropProcCallback(
|
|
Widget w,
|
|
XtPointer client,
|
|
XtPointer call )
|
|
{
|
|
XmDropProcCallbackStruct *cb = (XmDropProcCallbackStruct *) call;
|
|
|
|
if (cb->dropAction != XmDROP_HELP) {
|
|
HandleDrop(w, cb);
|
|
} else {
|
|
Arg args[2];
|
|
|
|
XtSetArg(args[0], XmNtransferStatus, XmTRANSFER_FAILURE);
|
|
XtSetArg(args[1], XmNnumDropTransfers, 0);
|
|
XmDropTransferStart(cb->dragContext, args, 2);
|
|
}
|
|
}
|
|
|
|
static void
|
|
RegisterDropSite(
|
|
Widget w )
|
|
{
|
|
Atom targets[4];
|
|
Arg args[10];
|
|
int n;
|
|
char * tmp_string = "ABC"; /* these are characters in XPCS, so... safe */
|
|
XTextProperty tmp_prop;
|
|
int status = 0;
|
|
|
|
tmp_prop.value = NULL;
|
|
status = XmbTextListToTextProperty(XtDisplay(w), &tmp_string, 1,
|
|
(XICCEncodingStyle)XTextStyle, &tmp_prop);
|
|
if (status == Success)
|
|
targets[0] = tmp_prop.encoding;
|
|
else
|
|
targets[0] = 99999; /* XmbTextList... should never fail for XPCS
|
|
* characters. But just in case someones
|
|
* Xlib is broken, this prevents a core dump.
|
|
*/
|
|
|
|
if (tmp_prop.value != NULL) XFree((char *)tmp_prop.value);
|
|
|
|
targets[1] = XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False);
|
|
targets[2] = XA_STRING;
|
|
targets[3] = XmInternAtom(XtDisplay(w), "TEXT", False);
|
|
|
|
n = 0;
|
|
XtSetArg(args[n], XmNimportTargets, targets); n++;
|
|
XtSetArg(args[n], XmNnumImportTargets, 4); n++;
|
|
/* XtSetArg(args[n], XmNdragProc, DragProcCallback); n++; */
|
|
XtSetArg(args[n], XmNdropProc, DropProcCallback); n++;
|
|
XmDropSiteRegister(w, args, n);
|
|
}
|
|
|
|
|
|
/*
|
|
* DRAG SITE code
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
StartDrag(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *num_params )
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
Atom targets[4];
|
|
char * tmp_string = "ABC"; /* these are characters in XPCS, so... safe */
|
|
XTextProperty tmp_prop;
|
|
int status = 0;
|
|
Cardinal num_targets = 0;
|
|
Widget drag_icon;
|
|
Arg args[10];
|
|
int n = 0;
|
|
|
|
tmp_prop.value = NULL;
|
|
status = XmbTextListToTextProperty(XtDisplay(w), &tmp_string, 1,
|
|
(XICCEncodingStyle)XTextStyle, &tmp_prop);
|
|
if (status == Success)
|
|
targets[num_targets++] = tmp_prop.encoding;
|
|
else
|
|
targets[num_targets++] = 99999; /* XmbTextList... should never fail
|
|
* for XPCS characters. But just in
|
|
* case someones Xlib is broken,
|
|
* this prevents a core dump.
|
|
*/
|
|
|
|
if (tmp_prop.value != NULL) XFree((char *)tmp_prop.value);
|
|
|
|
targets[num_targets++] = XmInternAtom(XtDisplay(w), "COMPOUND_TEXT", False);
|
|
targets[num_targets++] = XA_STRING;
|
|
targets[num_targets++] = XmInternAtom(XtDisplay(w), "TEXT", False);
|
|
|
|
drag_icon = (Widget) XmeGetTextualDragIcon(w);
|
|
|
|
n = 0;
|
|
XtSetArg(args[n], XmNcursorBackground, tw->core.background_pixel); n++;
|
|
XtSetArg(args[n], XmNcursorForeground, tw->primitive.foreground); n++;
|
|
XtSetArg(args[n], XmNsourceCursorIcon, drag_icon); n++;
|
|
XtSetArg(args[n], XmNexportTargets, targets); n++;
|
|
XtSetArg(args[n], XmNnumExportTargets, num_targets); n++;
|
|
XtSetArg(args[n], XmNconvertProc, _DtTermPrimSelectConvert); n++;
|
|
XtSetArg(args[n], XmNclientData, w); n++;
|
|
XtSetArg(args[n], XmNdragOperations, ( XmDROP_COPY)); n++;
|
|
(void) XmDragStart(w, event, args, n);
|
|
}
|
|
|
|
static Position
|
|
GetXFromPos(Widget w, XmTextPosition pos)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
TermBuffer pb;
|
|
short row,col;
|
|
TermCharInfoRec charInfoRec ;
|
|
|
|
posToBufferRowCol(tw,pos,&pb,&row,&col) ;
|
|
return(tpd->offsetX+col*tpd->cellWidth);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
void
|
|
_DtTermPrimSelectProcessBDrag(
|
|
Widget w,
|
|
XEvent *event,
|
|
char **params,
|
|
Cardinal *num_params )
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
TermSelectInfo selectInfo =
|
|
((DtTermPrimitiveWidget)w)->term.tpd->selectInfo;
|
|
XmTextPosition position, left, right;
|
|
Position left_x, left_y, right_x, right_y;
|
|
/* InputData data = tw->text.input->data; */
|
|
|
|
selectInfo->cancel = False;
|
|
position = xyToPos(tw, event->xbutton.x, event->xbutton.y);
|
|
|
|
if (_DtTermPrimSelectGetSelection(w, &left, &right) &&
|
|
(right != left)) {
|
|
if ((position > left && position < right)
|
|
|| (position == left &&
|
|
event->xbutton.x > GetXFromPos(w, left))
|
|
|| (position == right &&
|
|
event->xbutton.x < GetXFromPos(w, right))) {
|
|
selectInfo->sel_start = False;
|
|
StartDrag(w, event, params, num_params);
|
|
}
|
|
else
|
|
{
|
|
selectInfo->sel_start = True ;
|
|
}
|
|
}
|
|
else selectInfo->sel_start = True ;
|
|
}
|
|
|
|
|
|
/* This is the menu interface for copy clipboard */
|
|
Boolean
|
|
_DtTermPrimSelectCopyClipboard
|
|
(
|
|
Widget w,
|
|
Time copy_time
|
|
)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
XmTextPosition begin;
|
|
XmTextPosition end;
|
|
|
|
char *selected_string = NULL; /* text selection */
|
|
long item_id = 0L; /* clipboard item id */
|
|
long data_id = 0L; /* clipboard data id */
|
|
int status; /* clipboard status */
|
|
XmString clip_label;
|
|
XTextProperty tmp_prop;
|
|
Display *display = XtDisplay(w);
|
|
Window window = XtWindow(w);
|
|
char *atom_name;
|
|
|
|
if ( _DtTermPrimSelectGetSelection(w, &begin, &end) && begin != end ) {
|
|
selected_string = getString(w, begin, end, False);
|
|
}
|
|
/*
|
|
* Using the Xm clipboard facilities,
|
|
* copy the selected text to the clipboard
|
|
*/
|
|
tmp_prop.value = NULL;
|
|
if (selected_string != NULL) {
|
|
clip_label = XmStringCreateLocalized ("XM_TERM");
|
|
/* start copy to clipboard */
|
|
status = XmClipboardStartCopy(display, window, clip_label, copy_time,
|
|
w, NULL, &item_id);
|
|
|
|
if (status != ClipboardSuccess) {
|
|
XtFree(selected_string);
|
|
XmStringFree(clip_label);
|
|
return False;
|
|
}
|
|
|
|
status = XmbTextListToTextProperty(display, &selected_string, 1,
|
|
(XICCEncodingStyle)XStdICCTextStyle,
|
|
&tmp_prop);
|
|
|
|
if (status != Success && status <= 0) {
|
|
XmClipboardCancelCopy(display, window, item_id);
|
|
XtFree(selected_string);
|
|
XmStringFree(clip_label);
|
|
return False;
|
|
}
|
|
|
|
atom_name = XGetAtomName(display, tmp_prop.encoding);
|
|
|
|
/* move the data to the clipboard */
|
|
status = XmClipboardCopy(display, window, item_id, atom_name,
|
|
(XtPointer)tmp_prop.value, tmp_prop.nitems,
|
|
0, &data_id);
|
|
|
|
XtFree(atom_name);
|
|
|
|
if (status != ClipboardSuccess) {
|
|
XmClipboardCancelCopy(display, window, item_id);
|
|
XFree((char*)tmp_prop.value);
|
|
XmStringFree(clip_label);
|
|
return False;
|
|
}
|
|
|
|
/* end the copy to the clipboard */
|
|
status = XmClipboardEndCopy (display, window, item_id);
|
|
|
|
XtFree((char*)tmp_prop.value);
|
|
XmStringFree(clip_label);
|
|
|
|
if (status != ClipboardSuccess) return False;
|
|
} else
|
|
return False;
|
|
|
|
if (selected_string!=NULL)
|
|
XtFree(selected_string);
|
|
return True;
|
|
}
|
|
|
|
/* This is the event interface for copy clipboard */
|
|
void
|
|
_DtTermPrimSelectCopyClipboardEventIF
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *num_params
|
|
)
|
|
{
|
|
_DtTermPrimSelectCopyClipboard(w,event->xkey.time) ;
|
|
}
|
|
|
|
/*
|
|
* Retrieves the current data from the clipboard
|
|
* and paste it at the current cursor position
|
|
*/
|
|
Boolean
|
|
_DtTermPrimSelectPasteClipboard
|
|
(
|
|
Widget w
|
|
)
|
|
{
|
|
XmTextPosition sel_left = 0;
|
|
XmTextPosition sel_right = 0;
|
|
XmTextPosition paste_pos_left, paste_pos_right, cursorPos;
|
|
int status; /* clipboard status */
|
|
char * buffer; /* temporary text buffer */
|
|
unsigned long length; /* length of buffer */
|
|
unsigned long outlength = 0L; /* length of bytes copied */
|
|
long private_id = 0L; /* id of item on clipboard */
|
|
Boolean dest_disjoint = True;
|
|
XmTextBlockRec block, newblock;
|
|
Display *display = XtDisplay(w);
|
|
Window window = XtWindow(w);
|
|
Boolean get_ct = False;
|
|
Boolean freeBlock;
|
|
XTextProperty tmp_prop;
|
|
int malloc_size = 0;
|
|
int num_vals;
|
|
char **tmp_value;
|
|
char * total_tmp_value = NULL;
|
|
int i;
|
|
|
|
status = XmClipboardInquireLength(display, window, "STRING", &length);
|
|
|
|
if (status == ClipboardNoData || length == 0) {
|
|
status = XmClipboardInquireLength(display, window, "COMPOUND_TEXT",
|
|
&length);
|
|
if (status == ClipboardNoData || length == 0) return False;
|
|
get_ct = True;
|
|
}
|
|
|
|
/* malloc length of clipboard data */
|
|
buffer = XtMalloc((unsigned) length);
|
|
|
|
if (!get_ct) {
|
|
status = XmClipboardRetrieve(display, window, "STRING", buffer,
|
|
length, &outlength, &private_id);
|
|
} else {
|
|
status = XmClipboardRetrieve(display, window, "COMPOUND_TEXT",
|
|
buffer, length, &outlength, &private_id);
|
|
}
|
|
|
|
|
|
if (status != ClipboardSuccess) {
|
|
XmClipboardEndRetrieve(display, window);
|
|
XtFree(buffer);
|
|
return False;
|
|
}
|
|
|
|
tmp_prop.value = (unsigned char *) buffer;
|
|
if (!get_ct)
|
|
tmp_prop.encoding = XA_STRING;
|
|
else
|
|
tmp_prop.encoding = XmInternAtom(display, "COMPOUND_TEXT", False);
|
|
|
|
tmp_prop.format = 8;
|
|
tmp_prop.nitems = outlength;
|
|
num_vals = 0;
|
|
|
|
status = XmbTextPropertyToTextList(display, &tmp_prop, &tmp_value,
|
|
&num_vals);
|
|
|
|
/* if no conversions, num_vals doesn't change */
|
|
if (num_vals && (status == Success || status > 0)) {
|
|
for (i = 0; i < num_vals ; i++)
|
|
malloc_size += strlen(tmp_value[i]);
|
|
|
|
total_tmp_value = XtMalloc ((unsigned) malloc_size + 1);
|
|
total_tmp_value[0] = '\0';
|
|
for (i = 0; i < num_vals ; i++)
|
|
strcat(total_tmp_value, tmp_value[i]);
|
|
block.ptr = total_tmp_value;
|
|
block.length = strlen(total_tmp_value);
|
|
block.format = XmFMT_8_BIT;
|
|
XFreeStringList(tmp_value);
|
|
} else {
|
|
malloc_size = 1; /* to force space to be freed */
|
|
total_tmp_value = XtMalloc ((unsigned)1);
|
|
*total_tmp_value = '\0';
|
|
block.ptr = total_tmp_value;
|
|
block.length = 0;
|
|
block.format = XmFMT_8_BIT;
|
|
}
|
|
|
|
/* add new text */
|
|
if ( block.length )
|
|
{
|
|
char *pChar, *pCharEnd, *pCharFollow;
|
|
|
|
pCharEnd = block.ptr + block.length;
|
|
pCharFollow = (char *)block.ptr;
|
|
|
|
for (pChar = (char *)block.ptr; pChar < pCharEnd; pChar++)
|
|
{
|
|
if (*pChar == '\n')
|
|
{
|
|
*pChar = '\r';
|
|
DtTermSubprocSend(w, (unsigned char *) pCharFollow,
|
|
pChar - pCharFollow + 1);
|
|
pCharFollow = pChar + 1;
|
|
}
|
|
}
|
|
if (pCharFollow < pCharEnd)
|
|
{
|
|
DtTermSubprocSend(w, (unsigned char *) pCharFollow,
|
|
pCharEnd - pCharFollow);
|
|
}
|
|
}
|
|
XtFree(buffer);
|
|
if (malloc_size != 0) XtFree(total_tmp_value);
|
|
|
|
(void) _DtTermPrimCursorOn(w);
|
|
|
|
return True;
|
|
}
|
|
|
|
/* This is the event interface for paste clipboard */
|
|
void
|
|
_DtTermPrimSelectPasteClipboardEventIF
|
|
(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *num_params
|
|
)
|
|
{
|
|
_DtTermPrimSelectPasteClipboard(w) ;
|
|
}
|
|
|
|
/*
|
|
* This is for the SUN two button mouse
|
|
*/
|
|
static Bool
|
|
LookForButton (
|
|
Display * display,
|
|
XEvent * event,
|
|
XPointer arg)
|
|
{
|
|
|
|
#define DAMPING 5
|
|
#define ABS_DELTA(x1, x2) (x1 < x2 ? x2 - x1 : x1 - x2)
|
|
|
|
if( event->type == MotionNotify) {
|
|
XEvent * press = (XEvent *) arg;
|
|
|
|
if (ABS_DELTA(press->xbutton.x_root, event->xmotion.x_root) > DAMPING ||
|
|
ABS_DELTA(press->xbutton.y_root, event->xmotion.y_root) > DAMPING)
|
|
return(True);
|
|
}
|
|
else if (event->type == ButtonRelease)
|
|
return(True);
|
|
return(False);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static Boolean
|
|
XmTestInSelection(
|
|
Widget w,
|
|
XEvent *event )
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
XmTextPosition position, left, right;
|
|
Position left_x, right_x, dummy;
|
|
|
|
position = xyToPos(tw, event->xbutton.x, event->xbutton.y);
|
|
|
|
if ((!(_DtTermPrimSelectGetSelection(w, &left, &right) &&
|
|
(left != right && (position > left && position < right)))
|
|
|| (position == left &&
|
|
event->xbutton.x > GetXFromPos(w, left))
|
|
|| (position == right &&
|
|
event->xbutton.x < GetXFromPos(w, right)))
|
|
||
|
|
/* or if it is part of a multiclick sequence */
|
|
(event->xbutton.time > selectInfo->lastTime &&
|
|
event->xbutton.time - selectInfo->lastTime <
|
|
XtGetMultiClickTime(XtDisplay((Widget)w))) )
|
|
return(False);
|
|
else {
|
|
/* The determination of whether this is a transfer drag cannot be made
|
|
until a Motion event comes in. It is not a drag as soon as a
|
|
ButtonUp event happens or the MultiClickTimeout expires. */
|
|
XEvent new;
|
|
|
|
XPeekIfEvent(XtDisplay(w), &new, LookForButton, (XPointer)event);
|
|
switch (new.type) {
|
|
case MotionNotify:
|
|
return(True);
|
|
break;
|
|
case ButtonRelease:
|
|
return(False);
|
|
break;
|
|
}
|
|
return(False);
|
|
}
|
|
}
|
|
|
|
#define SELECTION_ACTION 0
|
|
#define TRANSFER_ACTION 1
|
|
|
|
/* ARGSUSED */
|
|
void
|
|
_DtTermPrimSelect2ButtonMouse(
|
|
Widget w,
|
|
XEvent *event,
|
|
char **params,
|
|
Cardinal *num_params )
|
|
{
|
|
/* This action happens when Button1 is pressed and the Selection
|
|
and Transfer are integrated on Button1. It is passed two
|
|
parameters: the action to call when the event is a selection,
|
|
and the action to call when the event is a transfer. */
|
|
|
|
if (*num_params != 2 /* || !XmIsTextField(w) */)
|
|
return;
|
|
if (XmTestInSelection(w, event))
|
|
XtCallActionProc(w, params[TRANSFER_ACTION], event, params, *num_params);
|
|
else
|
|
XtCallActionProc(w, params[SELECTION_ACTION], event, params, *num_params);
|
|
}
|
|
|
|
|
|
void
|
|
_DtTermPrimSelectProcessCancel(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *num_params )
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget)w;
|
|
TermSelectInfo selectInfo = tw->term.tpd->selectInfo;
|
|
XmTextPosition left_x, right_x;
|
|
|
|
XmParentInputActionRec p_event ;
|
|
|
|
if (!tw->term.allowOsfKeysyms) {
|
|
_DtTermPrimActionKeyInput(w,event,params,num_params);
|
|
return;
|
|
}
|
|
|
|
selectInfo->cancel = True ;
|
|
|
|
/* turn off the cursor */
|
|
_DtTermPrimCursorOff(w);
|
|
|
|
/* reset to origLeft and origRight */
|
|
setSelection (tw, selectInfo->origBegin, selectInfo->origEnd,
|
|
event->xkey.time, False) ;
|
|
|
|
/* turn on the cursor */
|
|
_DtTermPrimCursorOn(w);
|
|
|
|
if (selectInfo->selectID) {
|
|
XtRemoveTimeOut(selectInfo->selectID);
|
|
selectInfo->selectID = 0;
|
|
}
|
|
}
|