mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Mostly missing headers, explicit parentheses and new prototypes. Some Caveats: * I haven't compile-tested the SVR4 getpty file, it might need another tweak * There were operator precedence bugs in TermPrimCursor.c and TermPrimRender.c (^ vs. !=). This might change behaviour, but at least I haven't experienced any crashes ... * This adds a little more dependencies for include ordering, but unless we want to play the "headers that include headers that include headers..." game, this is unavoidable.
940 lines
30 KiB
C
940 lines
30 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 librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
#ifndef lint
|
|
#ifdef VERBOSE_REV_INFO
|
|
static char rcs_id[] = "$XConsortium: TermPrimScroll.c /main/1 1996/04/21 19:19:17 drk $";
|
|
#endif /* VERBOSE_REV_INFO */
|
|
#endif /* lint */
|
|
|
|
/* *
|
|
* (c) Copyright 1993, 1994 Hewlett-Packard Company *
|
|
* (c) Copyright 1993, 1994 International Business Machines Corp. *
|
|
* (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
|
|
* (c) Copyright 1993, 1994 Novell, Inc. *
|
|
*/
|
|
|
|
#include "TermHeader.h"
|
|
#include "TermPrimDebug.h"
|
|
#include "TermPrimP.h"
|
|
#include "TermPrimI.h"
|
|
#include "TermPrimData.h"
|
|
#include "TermPrimBuffer.h"
|
|
|
|
static void
|
|
waitOnCopyArea(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
struct termData *tpd = tw->term.tpd;
|
|
XEvent event;
|
|
XEvent *ev = &event;
|
|
|
|
while (tpd->scrollInProgress) {
|
|
(void) XWindowEvent(XtDisplay(w), XtWindow(w), ExposureMask, ev);
|
|
switch (ev->type) {
|
|
case Expose:
|
|
Debug('e', fprintf(stderr,
|
|
">>_waitOnCopyArea() Expose event received\n"));
|
|
|
|
/* refresh the border... */
|
|
(void) _DtTermPrimDrawShadow(w);
|
|
|
|
/* just refresh the exposed area...
|
|
*/
|
|
Debug('e', fprintf(stderr,
|
|
">>_waitOnCopyArea() exposing Expose area\n"));
|
|
Debug('e', fprintf(stderr,
|
|
">> x=%d y=%d width=%d height=%d\n",
|
|
ev->xexpose.x, ev->xexpose.y,
|
|
ev->xexpose.width, ev->xexpose.height));
|
|
(void) _DtTermPrimExposeText(w, ev->xexpose.x, ev->xexpose.y,
|
|
ev->xexpose.width, ev->xexpose.height, True);
|
|
break;
|
|
|
|
case GraphicsExpose:
|
|
/* refresh the exposed area and, if this is the last graphics
|
|
* exposure, we are done and can fall through to the noExpose
|
|
* code...
|
|
*/
|
|
Debug('e', fprintf(stderr,
|
|
">>_DtTermPrimScrollWait() GraphicsExpose event received, count=%d\n",
|
|
ev->xgraphicsexpose.count));
|
|
Debug('e', fprintf(stderr,
|
|
">>_waitOnCopyArea() exposing GraphicsExpose area\n"));
|
|
Debug('e', fprintf(stderr,
|
|
">> x=%d y=%d width=%d height=%d\n",
|
|
ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
|
|
ev->xgraphicsexpose.width, ev->xgraphicsexpose.height));
|
|
(void) _DtTermPrimExposeText(w,
|
|
ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
|
|
ev->xgraphicsexpose.width, ev->xgraphicsexpose.height,
|
|
False);
|
|
if (ev->xgraphicsexpose.count > 0) {
|
|
/* more to come... */
|
|
break;
|
|
}
|
|
|
|
case NoExpose:
|
|
/* we are done... */
|
|
Debug('e', fprintf(stderr,
|
|
">>_waitOnCopyArea() NoExpose event received\n"));
|
|
tpd->scrollInProgress = False;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
_DtTermPrimScrollWait(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
struct termData *tpd = tw->term.tpd;
|
|
int i;
|
|
int exposeY;
|
|
int exposeHeight;
|
|
int scrolledLines;
|
|
|
|
Debug('s', fprintf(stderr, ">>_DtTermPrimScrollWait() starting\n"));
|
|
Debug('s', fprintf(stderr,
|
|
">>_DtTermPrimScrollWait() scrollLines=%d, scrollsPending=%d\n",
|
|
tpd->scroll.jump.scrollLines, tpd->scroll.jump.scrollsPending));
|
|
|
|
/* make sure the cursor is off... */
|
|
(void) _DtTermPrimCursorOff(w);
|
|
|
|
if (tpd->scroll.jump.scrollLines != 0) {
|
|
/* flush so that we can be sure the output was visible before we
|
|
* scroll it off...
|
|
*/
|
|
(void) XFlush(XtDisplay(w));
|
|
|
|
/* figure out the height of the copy area... */
|
|
if (tpd->scroll.jump.scrollLines > 0) {
|
|
/* scrolling memory up... */
|
|
Debug('s', fprintf(stderr,
|
|
">>_DtTermPrimScrollWait() up, scrollLines=%d cellHeight=%d\n",
|
|
tpd->scroll.jump.scrollLines, tpd->cellHeight));
|
|
if (tpd->scroll.jump.scrollLines >=
|
|
tpd->scrollBottomRow - tpd->scrollTopRow + 1) {
|
|
/* a full screen or more -- we can avoid the copy area... */
|
|
tpd->scrollHeight = 0;
|
|
exposeY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow);
|
|
exposeHeight = tpd->cellHeight *
|
|
(tpd->scrollBottomRow - tpd->scrollTopRow + 1);
|
|
Debug('s', fprintf(stderr,
|
|
">>_DtTermPrimScrollWait() height=%d expose Y=%d height=%d\n",
|
|
tpd->scrollHeight, exposeY, exposeHeight));
|
|
} else {
|
|
tpd->scrollHeight = tpd->cellHeight *
|
|
(tpd->scrollBottomRow - tpd->scrollTopRow + 1 -
|
|
tpd->scroll.jump.scrollLines);
|
|
tpd->scrollSrcY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow + tpd->scroll.jump.scrollLines);
|
|
tpd->scrollDestY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow);
|
|
exposeY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollBottomRow + 1 -
|
|
tpd->scroll.jump.scrollLines);
|
|
exposeHeight = tpd->cellHeight *
|
|
(tpd->scroll.jump.scrollLines);
|
|
Debug('s', fprintf(stderr,
|
|
">>_DtTermPrimScrollWait() height=%d SrcY=%d DestY=%d expose Y=%d height=%d\n",
|
|
tpd->scrollHeight, tpd->scrollSrcY, tpd->scrollDestY,
|
|
exposeY, exposeHeight));
|
|
}
|
|
} else {
|
|
/* scrolling memory down... */
|
|
Debug('s', fprintf(stderr,
|
|
">>_DtTermPrimScrollWait() down, scrollLines=%d cellHeight=%d\n",
|
|
tpd->scroll.jump.scrollLines, tpd->cellHeight));
|
|
if (tpd->scroll.jump.scrollLines <=
|
|
-(tpd->scrollBottomRow - tpd->scrollTopRow + 1)) {
|
|
/* a full screen or more -- we can avoid the copy area... */
|
|
tpd->scrollHeight = 0;
|
|
exposeY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow);
|
|
exposeHeight = tpd->cellHeight *
|
|
(tpd->scrollBottomRow - tpd->scrollTopRow + 1);
|
|
Debug('s', fprintf(stderr,
|
|
">>_DtTermPrimScrollWait() height=%d expose Y=%d height=%d\n",
|
|
tpd->scrollHeight, exposeY, exposeHeight));
|
|
} else {
|
|
/* remember: scrollLines is **NEGATIVE**...
|
|
*/
|
|
tpd->scrollHeight = tpd->cellHeight * (tpd->scrollBottomRow -
|
|
tpd->scrollTopRow + 1 - -tpd->scroll.jump.scrollLines);
|
|
tpd->scrollSrcY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow);
|
|
tpd->scrollDestY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow + -tpd->scroll.jump.scrollLines);
|
|
exposeY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow);
|
|
exposeHeight = tpd->cellHeight *
|
|
(-tpd->scroll.jump.scrollLines);
|
|
Debug('s', fprintf(stderr,
|
|
">>_DtTermPrimScrollWait() height=%d SrcY=%d DestY=%d expose Y=%d height=%d\n",
|
|
tpd->scrollHeight, tpd->scrollSrcY, tpd->scrollDestY,
|
|
exposeY, exposeHeight));
|
|
}
|
|
}
|
|
|
|
/* we need to do a copy area... */
|
|
if (tpd->scrollHeight > 0) {
|
|
/* calculate scroll area... */
|
|
tpd->scrollWidth = tpd->cellWidth * tw->term.columns;
|
|
tpd->scrollSrcX = tpd->offsetX;
|
|
tpd->scrollDestX = tpd->offsetX;
|
|
|
|
(void) XCopyArea(XtDisplay(w),
|
|
/* Display */
|
|
XtWindow(w), /* Source */
|
|
XtWindow(w), /* Destination */
|
|
tpd->renderGC.gc, /* GC */
|
|
tpd->scrollSrcX, /* source X */
|
|
tpd->scrollSrcY, /* source Y */
|
|
tpd->scrollWidth, /* width */
|
|
tpd->scrollHeight, /* height */
|
|
tpd->scrollDestX, /* destination X */
|
|
tpd->scrollDestY); /* destination Y */
|
|
tpd->scrollInProgress = True;
|
|
}
|
|
|
|
/* expose the exposed area. We need to expose the exposed area
|
|
* as well as any lines that have been changed. While we really
|
|
* could just expose the exposed area and then go back and fill
|
|
* in any remaining lines that have the flag set, we will first
|
|
* fill in any lines above the expose area with their flag set,
|
|
* fill in the expose area, and then fill in any lines below
|
|
* the expose area with their flag set. This fills things in
|
|
* from top to bottom which is much more pleasing visually.
|
|
*/
|
|
Debug('s', fprintf(stderr,
|
|
">>_DtTermPrimScrollWait() exposing scroll area\n"));
|
|
Debug('s', fprintf(stderr,
|
|
">> x=%d y=%d width=%d height=%d\n",
|
|
tpd->offsetX,
|
|
exposeY,
|
|
tpd->cellWidth * tw->term.columns,
|
|
exposeHeight));
|
|
|
|
/* set scrollLines == 0, or renderText will not render them... */
|
|
scrolledLines = tpd->scroll.jump.scrollLines;
|
|
tpd->scroll.jump.scrollLines = 0;
|
|
/* clear the scrolled flag... */
|
|
tpd->scroll.jump.scrolled = False;
|
|
|
|
/* refresh any lines above the expose zone that have their
|
|
* scrollRefreshRows flag set...
|
|
*/
|
|
for (i = 0; i < (exposeY - tpd->offsetX) / tpd->cellHeight; i++) {
|
|
if (tpd->scrollRefreshRows[i]) {
|
|
(void) _DtTermPrimRefreshText(w, 0, i, tw->term.columns, i);
|
|
}
|
|
}
|
|
/* expose the refresh expose area... */
|
|
(void) _DtTermPrimExposeText(w,
|
|
tpd->offsetX,
|
|
exposeY,
|
|
tpd->cellWidth * tw->term.columns,
|
|
exposeHeight,
|
|
False);
|
|
|
|
/* refresh any lines below the expose zone that have their
|
|
* scrollRefreshRows flag set...
|
|
*/
|
|
for (i = (exposeY - tpd->offsetX + exposeHeight) / tpd->cellHeight;
|
|
i < tw->term.rows; i++) {
|
|
if (tpd->scrollRefreshRows[i]) {
|
|
(void) _DtTermPrimRefreshText(w, 0, i, tw->term.columns, i);
|
|
}
|
|
}
|
|
|
|
if (tpd->scrollHeight > 0)
|
|
tpd->scroll.jump.scrollsPending++;
|
|
|
|
(void) _DtTermPrimCursorUpdate(w);
|
|
} else {
|
|
/* scrollLines == 0...
|
|
*/
|
|
|
|
/* flush so that we can be sure the output was visible before we
|
|
* scroll it off...
|
|
*/
|
|
(void) XFlush(XtDisplay(w));
|
|
|
|
/* clear the scrolled flag... */
|
|
tpd->scroll.jump.scrolled = False;
|
|
|
|
/* refresh any lines below the expose zone that have their
|
|
* scrollRefreshRows flag set...
|
|
*/
|
|
|
|
for (i = 0; i < tw->term.rows; i++) {
|
|
if (tpd->scrollRefreshRows[i]) {
|
|
(void) _DtTermPrimRefreshText(w, 0, i, tw->term.columns, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
while (tpd->scroll.jump.scrollsPending > 0) {
|
|
(void) waitOnCopyArea(w);
|
|
tpd->scroll.jump.scrollsPending--;
|
|
}
|
|
|
|
Debug('s', fprintf(stderr, ">>_DtTermPrimScrollWait() finished\n"));
|
|
}
|
|
|
|
static void
|
|
doActualScroll(Widget w, int lines)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
struct termData *tpd = tw->term.tpd;
|
|
int exposeY;
|
|
int exposeHeight;
|
|
int i;
|
|
|
|
/* make sure the cursor is off... */
|
|
(void) _DtTermPrimCursorOff(w);
|
|
|
|
/* figure out the height of the copy area... */
|
|
if (lines > 0) {
|
|
/* scrolling memory up... */
|
|
if (lines >= tpd->scrollBottomRow - tpd->scrollTopRow + 1) {
|
|
/* we are scrolling a full screen or more, so there is nothing
|
|
* to copy...
|
|
*/
|
|
tpd->scrollHeight = 0;
|
|
exposeY = tpd->offsetY + tpd->cellHeight * tpd->scrollTopRow;
|
|
exposeHeight = tpd->cellHeight *
|
|
(tpd->scrollBottomRow - tpd->scrollTopRow + 1);
|
|
} else {
|
|
tpd->scrollHeight = tpd->cellHeight *
|
|
(tpd->scrollBottomRow - tpd->scrollTopRow + 1 - lines);
|
|
tpd->scrollSrcY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow + lines);
|
|
tpd->scrollDestY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow);
|
|
|
|
/* expose bottom lines lines... */
|
|
exposeY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollBottomRow + 1 - lines);
|
|
exposeHeight = tpd->cellHeight * lines;
|
|
}
|
|
} else {
|
|
/* scrolling memory down... */
|
|
/* lines are negative -- make positive... */
|
|
lines = -lines;
|
|
if (lines >= tw->term.rows) {
|
|
/* we are scrolling a full screen or more, so there is nothing
|
|
* to copy...
|
|
*/
|
|
tpd->scrollHeight = 0;
|
|
exposeY = tpd->offsetY + tpd->cellHeight * tpd->scrollTopRow;
|
|
exposeHeight = tpd->cellHeight *
|
|
(tpd->scrollBottomRow - tpd->scrollTopRow + 1);
|
|
} else {
|
|
tpd->scrollHeight = tpd->cellHeight *
|
|
(tpd->scrollBottomRow - tpd->scrollTopRow + 1 - lines);
|
|
tpd->scrollSrcY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow);
|
|
tpd->scrollDestY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow + lines);
|
|
|
|
/* expose top lines lines... */
|
|
exposeY = tpd->offsetY + tpd->cellHeight *
|
|
(tpd->scrollTopRow);
|
|
exposeHeight = tpd->cellHeight * lines;
|
|
}
|
|
}
|
|
|
|
/* scroll the display... */
|
|
if (tpd->scrollHeight > 0) {
|
|
/* calculate scroll area... */
|
|
tpd->scrollWidth = tpd->cellWidth * tw->term.columns;
|
|
tpd->scrollSrcX = tpd->offsetX;
|
|
tpd->scrollDestX = tpd->offsetX;
|
|
|
|
/* copy the area... */
|
|
XCopyArea(XtDisplay(w), /* Display */
|
|
XtWindow(w), /* Source */
|
|
XtWindow(w), /* Destination */
|
|
tpd->renderGC.gc, /* GC */
|
|
tpd->scrollSrcX, /* source X */
|
|
tpd->scrollSrcY, /* source Y */
|
|
tpd->scrollWidth, /* width */
|
|
tpd->scrollHeight, /* height */
|
|
tpd->scrollDestX, /* destination X */
|
|
tpd->scrollDestY); /* destination Y */
|
|
tpd->scrollInProgress = True;
|
|
}
|
|
|
|
/* clear the old area... */
|
|
(void) XFillRectangle(XtDisplay(w), /* Display */
|
|
XtWindow(w), /* Drawable */
|
|
tpd->clearGC.gc, /* GC */
|
|
tpd->offsetX, /* x */
|
|
exposeY, /* y */
|
|
tw->term.columns * tpd->cellWidth,
|
|
/* width */
|
|
exposeHeight); /* height */
|
|
|
|
/* expose the old area... */
|
|
(void) _DtTermPrimExposeText(w,
|
|
tpd->offsetX,
|
|
exposeY,
|
|
tw->term.columns * tpd->cellWidth,
|
|
exposeHeight, False);
|
|
|
|
(void) _DtTermPrimCursorUpdate(w);
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function:
|
|
* _DtTermPrimScrollText(): scroll the terminal window
|
|
*
|
|
* Parameters:
|
|
* Widget w: widget to scroll
|
|
* int lines: lines to scroll
|
|
*
|
|
* Returns:
|
|
* <nothing>
|
|
*
|
|
* Notes:
|
|
*
|
|
* This function will scroll the terminals window. It supports
|
|
* both jump scroll and non-jump scroll (single line at a time).
|
|
* In jump scroll, the maximum number of lines that will be
|
|
* scrolled at a time is the length of the display. This insures
|
|
* that all text will be displayed for at least an instant.
|
|
*
|
|
* In jump scroll mode, scrolling is performed as follows:
|
|
*
|
|
* - Scroll request is made:
|
|
*
|
|
* + Number of lines to scroll is incremented.
|
|
*
|
|
* + If the number of lines is < the length of the screen,
|
|
* rendering is discontinued and the actual scroll request is
|
|
* delayed until the the cursor is turned back on (i.e.,
|
|
* select(2) says there is no more input on the pty).
|
|
*
|
|
* + If the number of lines is >= the length of the screen, the
|
|
* copy area is performed, and the world blocks on exposure
|
|
* events on the window. When a no-expose request, or the
|
|
* last graphics expose request is received, any remaining
|
|
* lines will be queue'ed up.
|
|
*
|
|
* - The code that processes data coming over the pty determines
|
|
* via select(2) that there is no data to be read.
|
|
*
|
|
* + The copy area is performed, and the world blocks on
|
|
* exposure events on the window. When a no-expose request,
|
|
* or the last graphics expose request is received, the
|
|
* scroll is complete.
|
|
*
|
|
*
|
|
* In non-jump scroll mode, the following actions are performed:
|
|
*
|
|
* - If there is no scroll in progress, the copy area is performed.
|
|
* Any additional input is processed as normal.
|
|
*
|
|
* - When the generated no-expose or final graphics expose event is
|
|
* processed, the pending scroll flag is cleared.
|
|
*
|
|
* - If there is a scroll in progress, the new scroll is queued up.
|
|
* Any remaining pty input will be queued and the pty will be
|
|
* dropped from Xt input select.
|
|
*
|
|
* - When the generated no-expose or final graphics expose event is
|
|
* processed, the queued copy area will be performed. Any queued
|
|
* pty input will be processed and the pty will be added to the
|
|
* Xt input select.
|
|
*/
|
|
|
|
void
|
|
_DtTermPrimScrollText(Widget w, short lines)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
struct termData *tpd = tw->term.tpd;
|
|
short oldTopRow;
|
|
short newTopRow;
|
|
int lines2;
|
|
int i;
|
|
|
|
/* figure out what our new top row will be. It is limitied by the
|
|
* beginning of memory (i.e., we can't scroll above line 0) and the
|
|
* lastUsedRow (i.e., we can't scroll the lastUsedRow off the screen).
|
|
* we will then use this value to clip lines...
|
|
*/
|
|
oldTopRow = tpd->topRow;
|
|
if (lines > 0) {
|
|
newTopRow = tpd->topRow + lines;
|
|
/* don't scroll past the lastUsedRow... */
|
|
if (newTopRow > (tpd->lastUsedRow - tpd->scrollLockTopRow)) {
|
|
newTopRow = tpd->lastUsedRow - tpd->scrollLockTopRow;
|
|
}
|
|
} else {
|
|
if (tpd->useHistoryBuffer) {
|
|
if ((tpd->topRow + tpd->lastUsedHistoryRow) >= -lines)
|
|
newTopRow = tpd->topRow - -lines;
|
|
else
|
|
newTopRow = -tpd->lastUsedHistoryRow;
|
|
} else {
|
|
if (tpd->topRow >= -lines)
|
|
newTopRow = tpd->topRow - -lines;
|
|
else
|
|
newTopRow = 0;
|
|
}
|
|
}
|
|
|
|
/* adjust lines to the clipped newTopRow... */
|
|
lines = newTopRow - oldTopRow;
|
|
|
|
/* we don't need to do any for 0... */
|
|
if (0 == lines)
|
|
return;
|
|
|
|
if ((tw->term.jumpScroll &&
|
|
((lines + tpd->scroll.jump.scrollLines) >
|
|
(tw->term.rows -
|
|
tpd->scrollLockTopRow -
|
|
(tw->term.rows - 1 - tpd->scrollLockBottomRow)))) ||
|
|
((lines + tpd->scroll.jump.scrollLines) <
|
|
-(tw->term.rows -
|
|
tpd->scrollLockTopRow -
|
|
(tw->term.rows - 1 - tpd->scrollLockBottomRow))) ||
|
|
(tpd->scrollTopRow != tpd->scrollLockTopRow) ||
|
|
(tpd->scrollBottomRow != tpd->scrollLockBottomRow)) {
|
|
/* scroll out the queued up jump scroll lines... */
|
|
if (tpd->scroll.jump.scrollLines != 0) {
|
|
(void) _DtTermPrimScrollWait(w);
|
|
}
|
|
}
|
|
|
|
/* move the memory locked region in screen memory...
|
|
*/
|
|
/* Assuming a 24 line buffer with lock on 10 and 20 and 30 lines
|
|
* of screen buffer, with one below and scrolling 3 lines, we do
|
|
* the following:
|
|
*
|
|
* oooooLLLLLLLLLL LLLLo
|
|
* ||||||||||||||||||||||||||||||
|
|
* 000000000011111111112222222222
|
|
* 012345678901234567890123456789
|
|
*
|
|
* move lines 15-17 to the top of the buffer:
|
|
*
|
|
* ooooooooLLLLLLLLLL LLLLo
|
|
* ||||||||||||||||||||||||||||||
|
|
* 111000000000011111112222222222
|
|
* 567012345678901234890123456789
|
|
*
|
|
* move line 29 to the bottom of the unlocked area:
|
|
*
|
|
* ooooooooLLLLLLLLLL LLLL
|
|
* ||||||||||||||||||||||||||||||
|
|
* 111000000000011111112222222222
|
|
* 567012345678901234890123495678
|
|
*
|
|
* clear the top2 lines and move it to the bottom of the
|
|
* unlocked area:
|
|
*
|
|
* ooooooLLLLLLLLLL LLLL
|
|
* ||||||||||||||||||||||||||||||
|
|
* 100000000001111111222221122222
|
|
* 701234567890123489012345695678
|
|
*
|
|
*/
|
|
|
|
/* if we have a history buffer and we are going to be scrolling lines
|
|
* off of the buffer, we should move them into the history buffer.
|
|
*/
|
|
if ((tpd->scrollLockTopRow == 0) &&
|
|
(tpd->scrollLockBottomRow >= (tw->term.rows - 1))) {
|
|
/*DKS*/
|
|
}
|
|
|
|
/* first move the top lock area... */
|
|
if (tpd->scrollLockTopRow > 0) {
|
|
(void) _DtTermPrimBufferMoveLockArea(tpd->termBuffer,
|
|
tpd->topRow + lines, tpd->topRow, tpd->scrollLockTopRow);
|
|
}
|
|
|
|
/* now move the bottom lock area... */
|
|
if (tpd->scrollLockBottomRow < (tw->term.rows - 1)) {
|
|
/* if we are moving up, let's move as many rows as we can from
|
|
* bottom offscreen memory...
|
|
*/
|
|
lines2 = 0;
|
|
|
|
if ((lines > 0) && (tpd->bufferRows > (tpd->topRow + tw->term.rows))) {
|
|
/* clip lines2 to the number of lines that we can obtain
|
|
* from the bottom of the buffer...
|
|
*/
|
|
lines2 = lines;
|
|
if (lines2 > (tpd->bufferRows - (tpd->topRow + tw->term.rows))) {
|
|
lines2 = tpd->bufferRows - (tpd->topRow + tw->term.rows);
|
|
}
|
|
|
|
if (lines2 > 0) {
|
|
/* move them... */
|
|
(void) _DtTermPrimBufferMoveLockArea(tpd->termBuffer,
|
|
tpd->topRow + tpd->scrollLockBottomRow - lines2,
|
|
tpd->topRow + tpd->scrollLockBottomRow,
|
|
(tw->term.rows - 1) - tpd->scrollLockBottomRow);
|
|
}
|
|
}
|
|
|
|
/* figure out how many lines we will need to take from the
|
|
* top...
|
|
*/
|
|
lines2 = lines - lines2;
|
|
if (lines2 > 0) {
|
|
for (i = 0; i < lines2; i++) {
|
|
(void) _DtTermPrimBufferClearLine(tpd->termBuffer, i, 0);
|
|
}
|
|
(void) _DtTermPrimBufferMoveLockArea(tpd->termBuffer,
|
|
0,
|
|
lines2,
|
|
tpd->topRow + tpd->scrollLockBottomRow + 1 - lines);
|
|
newTopRow -= lines2;
|
|
}
|
|
}
|
|
|
|
/* set topRow... */
|
|
tpd->topRow = newTopRow;
|
|
|
|
if (tw->term.jumpScroll) {
|
|
/* jump scroll...
|
|
*/
|
|
/* queue up the lines for scrolling... */
|
|
tpd->scroll.jump.scrollLines += lines;
|
|
tpd->scroll.jump.scrolled = True;
|
|
tpd->scrollTopRow = tpd->scrollLockTopRow;
|
|
tpd->scrollBottomRow = tpd->scrollLockBottomRow;
|
|
|
|
/* scroll out the scrollRefreshRows flags now... */
|
|
/* NOTE: we loose the refresh flag for all rows that are scrolled
|
|
* off. The result of this is that if we do a scroll up followed
|
|
* by a scroll down, we will (at a minimum) refresh the top and
|
|
* bottom lines. One workaround would be to tripple the buffer
|
|
* and keep the lines that get scrolled off the top or bottom.
|
|
* This would probably break something, since there are times
|
|
* that the scrolled off line gets modified or even cleared (such
|
|
* as delete line off of the top of the display), so this might
|
|
* not be a very good idea.
|
|
*/
|
|
if (lines > 0) {
|
|
/* scroll them up... */
|
|
for (i = tpd->scrollTopRow;
|
|
i <= tpd->scrollBottomRow - lines; i++) {
|
|
tpd->scrollRefreshRows[i] =
|
|
tpd->scrollRefreshRows[i + lines];
|
|
}
|
|
/* set the rest... */
|
|
for (; i <= tpd->scrollBottomRow; i++) {
|
|
tpd->scrollRefreshRows[i] = True;
|
|
}
|
|
} else {
|
|
/* remember, lines is negative... */
|
|
for (i = tpd->scrollBottomRow;
|
|
i >= tpd->scrollTopRow + -lines; i--) {
|
|
tpd->scrollRefreshRows[i] =
|
|
tpd->scrollRefreshRows[i - -lines];
|
|
}
|
|
for (; i >= tpd->scrollTopRow; i--) {
|
|
tpd->scrollRefreshRows[i] = True;
|
|
}
|
|
}
|
|
} else {
|
|
/* non jump-scroll...
|
|
*/
|
|
if (tpd->scrollInProgress) {
|
|
/* let's queue up the scroll and bail out...
|
|
*/
|
|
tpd->scroll.nojump.pendingScrollLines += lines;
|
|
/*DKS!!! v v v v v v v v v v v v v v v v v v v v v v */
|
|
if (tpd->scroll.nojump.pendingScrollLines > 1)
|
|
(void) fprintf(stderr,
|
|
"tell Dave _DtTermPrimScrollText has pendingScrollLines=%d\n",
|
|
tpd->scroll.nojump.pendingScrollLines);
|
|
/*DKS!!! ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ */
|
|
tpd->scroll.nojump.pendingScroll = True;
|
|
tpd->scroll.nojump.pendingScrollTopRow = tpd->scrollLockTopRow;
|
|
tpd->scroll.nojump.pendingScrollBottomRow = tpd->scrollLockBottomRow;
|
|
(void) _DtTermPrimStartOrStopPtyInput(w);
|
|
return;
|
|
}
|
|
|
|
/* no scroll in progress, let's scroll it... */
|
|
tpd->scrollTopRow = tpd->scrollLockTopRow;
|
|
tpd->scrollBottomRow = tpd->scrollLockBottomRow;
|
|
(void) doActualScroll(w, lines);
|
|
}
|
|
|
|
/* This case: (tpd->scrollLockTopRow > 0)
|
|
is handled elsewhere.
|
|
*/
|
|
if ( lines > 0 && tpd->scrollLockBottomRow < (tw->term.rows-1)) {
|
|
_DtTermPrimSelectMoveLines(w, tpd->scrollLockTopRow + lines,
|
|
tpd->scrollLockTopRow,
|
|
tpd->scrollLockBottomRow - tpd->scrollLockTopRow);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
_DtTermPrimScrollTextTo(Widget w, short topRow)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
struct termData *tpd = tw->term.tpd;
|
|
int oldTopRow;
|
|
|
|
if (topRow == tpd->topRow) {
|
|
/* already there... */
|
|
return;
|
|
}
|
|
|
|
(void) _DtTermPrimScrollText(w, topRow - tpd->topRow);
|
|
return;
|
|
}
|
|
|
|
void
|
|
_DtTermPrimScrollTextArea(Widget w, short scrollStart, short scrollLength,
|
|
short scrollDistance)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
struct termData *tpd = tw->term.tpd;
|
|
int oldTopRow;
|
|
int exposeY;
|
|
int exposeHeight;
|
|
int i;
|
|
|
|
#ifdef NOTDEF
|
|
if (scrollDistance > 0) {
|
|
/* scrolling text up... */
|
|
if (tpd->lastUsedRow <= tpd->topRow + scrollStart) {
|
|
/* scrolling past lastUsedRow -- nothing to scroll... */
|
|
return;
|
|
}
|
|
}
|
|
#endif /* NOTDEF */
|
|
/* clip the length... */
|
|
if (scrollStart + scrollLength > tw->term.rows) {
|
|
scrollLength = tw->term.rows - scrollStart;
|
|
}
|
|
|
|
/* we don't need to do anything for 0 distance... */
|
|
if (0 == scrollDistance) {
|
|
return;
|
|
}
|
|
|
|
/* if we are in jumpscroll mode and:
|
|
* -our region differs (scrollTopRow and scrollBottomRow), or
|
|
* -we are going to queue more lines than the scroll region
|
|
* we need to complete the queued scroll...
|
|
*/
|
|
if (tw->term.jumpScroll &&
|
|
((scrollDistance + tpd->scroll.jump.scrollLines > scrollLength) ||
|
|
(scrollDistance + tpd->scroll.jump.scrollLines < -scrollLength) ||
|
|
(tpd->scrollTopRow != scrollStart) ||
|
|
(tpd->scrollBottomRow != scrollStart + scrollLength - 1))) {
|
|
/* scroll out the queued up jump scroll lines... */
|
|
if (tpd->scroll.jump.scrolled != 0) {
|
|
(void) _DtTermPrimScrollWait(w);
|
|
}
|
|
}
|
|
|
|
if (tw->term.jumpScroll) {
|
|
/* jump scroll...
|
|
*/
|
|
/* queue up the lines for scrolling... */
|
|
tpd->scroll.jump.scrollLines += scrollDistance;
|
|
tpd->scroll.jump.scrolled = True;
|
|
tpd->scrollTopRow = scrollStart;
|
|
tpd->scrollBottomRow = scrollStart + scrollLength - 1;
|
|
|
|
/* scroll out the scrollRefreshRows flags now... */
|
|
if (scrollDistance > 0) {
|
|
/* scroll them up... */
|
|
for (i = tpd->scrollTopRow;
|
|
i <= tpd->scrollBottomRow - scrollDistance; i++) {
|
|
tpd->scrollRefreshRows[i] =
|
|
tpd->scrollRefreshRows[i + scrollDistance];
|
|
}
|
|
/* set the rest... */
|
|
for (; i <= tpd->scrollBottomRow; i++) {
|
|
tpd->scrollRefreshRows[i] = True;
|
|
}
|
|
} else {
|
|
for (i = tpd->scrollBottomRow;
|
|
i >= tpd->scrollTopRow + -scrollDistance; i--) {
|
|
tpd->scrollRefreshRows[i] =
|
|
tpd->scrollRefreshRows[i - -scrollDistance];
|
|
}
|
|
for (; i >= tpd->scrollTopRow; i--) {
|
|
tpd->scrollRefreshRows[i] = True;
|
|
}
|
|
}
|
|
} else {
|
|
/* non jump scroll...
|
|
*/
|
|
if (tpd->scrollInProgress) {
|
|
/* let's queue up the scroll and bail out...
|
|
*/
|
|
tpd->scroll.nojump.pendingScrollLines += scrollDistance;
|
|
/*DKS!!! v v v v v v v v v v v v v v v v v v v v v v */
|
|
if (tpd->scroll.nojump.pendingScrollLines > 1)
|
|
(void) fprintf(stderr,
|
|
"tell Dave _DtTermPrimScrollText has pendingScrollLines=%d\n",
|
|
tpd->scroll.nojump.pendingScrollLines);
|
|
/*DKS!!! ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ */
|
|
tpd->scroll.nojump.pendingScroll = True;
|
|
tpd->scroll.nojump.pendingScrollTopRow = scrollStart;
|
|
tpd->scroll.nojump.pendingScrollBottomRow =
|
|
scrollStart + scrollLength - 1;
|
|
(void) _DtTermPrimStartOrStopPtyInput(w);
|
|
return;
|
|
}
|
|
|
|
/* no scroll in progress, let's scroll it... */
|
|
tpd->scrollTopRow = scrollStart;
|
|
tpd->scrollBottomRow = scrollStart + scrollLength - 1;
|
|
(void) doActualScroll(w, scrollDistance);
|
|
tpd->scrollInProgress = True;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function:
|
|
* _DtTermPrimScrollComplete(): finish a scroll. This is normall called
|
|
* to complete a non-jump scroll, or if it is necessary to
|
|
* complete and flush any scroll.
|
|
*
|
|
* Parameters:
|
|
* Widget w: widget to scroll
|
|
*
|
|
* Returns:
|
|
* <nothing>
|
|
*
|
|
* Notes:
|
|
*
|
|
* This function is used in non-jump scroll only!!!
|
|
*
|
|
* This function is called by the Term widget when a no-expose or
|
|
* final graphics expose event is received (which was generated by
|
|
* the previous scroll's copy area). It will invoke the scroll that
|
|
* was queued up and caused pty input to be blocked.
|
|
*/
|
|
|
|
void
|
|
_DtTermPrimScrollComplete(Widget w, Boolean flush)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
struct termData *tpd = tw->term.tpd;
|
|
|
|
if (tw->term.jumpScroll) {
|
|
/* jump scroll...
|
|
*/
|
|
if (flush) {
|
|
/* we need to finish any pending scrolls...
|
|
*/
|
|
/* In jump scroll, all we need to do is to invoke the scroll.
|
|
* _DtTermPrimScrollWait() will perform the actual copy area and
|
|
* wait for the generated graphics expose / no expose events...
|
|
*/
|
|
if (tpd->scroll.jump.scrolled) {
|
|
Debug('s', fprintf(stderr,
|
|
">>_DtTermPrimScrollComplete() calling _DtTermPrimScrollWait()\n"));
|
|
(void) _DtTermPrimScrollWait(w);
|
|
}
|
|
}
|
|
} else {
|
|
/* non-jump scroll...
|
|
*/
|
|
|
|
if (flush && tpd->scrollInProgress) {
|
|
/* if we have a pending scroll, we need to wait for it to
|
|
* complete. Normally, we would service this out of the
|
|
* XtMainLoop() dispatch loop, but for some reason we need
|
|
* to do it now.
|
|
*/
|
|
(void) waitOnCopyArea(w);
|
|
tpd->scrollInProgress = False;
|
|
}
|
|
|
|
if (!tw->term.jumpScroll && tpd->scroll.nojump.pendingScroll) {
|
|
/* do the queued scroll... */
|
|
tpd->scrollTopRow = tpd->scroll.nojump.pendingScrollTopRow;
|
|
tpd->scrollBottomRow = tpd->scroll.nojump.pendingScrollBottomRow;
|
|
(void) doActualScroll(w, tpd->scroll.nojump.pendingScrollLines);
|
|
|
|
/* no lines pending, but there is a scroll in progress... */
|
|
tpd->scroll.nojump.pendingScrollLines = 0;
|
|
tpd->scrollInProgress = True;
|
|
tpd->scroll.nojump.pendingScroll = False;
|
|
|
|
if (flush) {
|
|
/* wait for it to complete...
|
|
*/
|
|
(void) waitOnCopyArea(w);
|
|
tpd->scrollInProgress = False;
|
|
|
|
/* If there is any pending input or if we need to reinstall
|
|
* the input select, force a pty read...
|
|
*/
|
|
(void) XtAppAddTimeOut(XtWidgetToApplicationContext(w),
|
|
0, _DtTermPrimForcePtyRead, (XtPointer) w);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
_DtTermPrimScrollCompleteIfNecessary(Widget w, short scrollTopRow,
|
|
short scrollBottomRow, short lines)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
struct termData *tpd = tw->term.tpd;
|
|
short maxJumpScrollLines;
|
|
|
|
if ((scrollTopRow != tpd->scrollTopRow) ||
|
|
(scrollBottomRow != tpd->scrollBottomRow)) {
|
|
(void) _DtTermPrimScrollComplete(w, True);
|
|
return;
|
|
}
|
|
|
|
if (tw->term.jumpScroll) {
|
|
maxJumpScrollLines = tpd->scrollBottomRow - tpd->scrollTopRow + 1;
|
|
if ((lines + tpd->scroll.jump.scrollLines > maxJumpScrollLines) ||
|
|
(lines + tpd->scroll.jump.scrollLines < -maxJumpScrollLines))
|
|
(void) _DtTermPrimScrollComplete(w, True);
|
|
return;
|
|
} else {
|
|
if (!tw->term.jumpScroll && tpd->scroll.nojump.pendingScroll) {
|
|
(void) _DtTermPrimScrollComplete(w, True);
|
|
return;
|
|
}
|
|
}
|
|
}
|