This shouldn't change behavior (or even object code) at all because those assignments are all without effect. Removing that code removes noise which helps working with code analysis tools.
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;
|
|
}
|
|
}
|