mirror of
https://github.com/sheumann/VNCviewGS.git
synced 2024-12-02 21:49:25 +00:00
1e7b5a13fe
This avoids situations where the system may seem unresponsive for some time (primarily, I think, due to network processing being relatively slow).
271 lines
9.4 KiB
C++
271 lines
9.4 KiB
C++
#if __ORCAC__
|
|
#pragma lint -1
|
|
#pragma noroot
|
|
segment "VNCview GS";
|
|
#endif
|
|
|
|
#include <window.h>
|
|
#include <quickdraw.h>
|
|
#include <qdaux.h>
|
|
#include <desk.h>
|
|
#include <memory.h>
|
|
#include <resources.h>
|
|
#include <tcpip.h>
|
|
#include <menu.h>
|
|
#include <control.h>
|
|
#include <misctool.h>
|
|
#include <scrap.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <event.h>
|
|
#include <limits.h>
|
|
|
|
#include "vncsession.h"
|
|
#include "vncview.h"
|
|
#include "vncdisplay.h"
|
|
#include "colortables.h"
|
|
#include "readtcp.h"
|
|
#include "raw.h"
|
|
|
|
#define EVENT_CHECK_INVERVAL 10 /* tick count between event checks */
|
|
|
|
/* Data on state of raw rectangle drawing routines */
|
|
static unsigned int lineBytes; /* Number of bytes in a line of GS pixels */
|
|
static unsigned long pixels;
|
|
|
|
static unsigned int drawingLine; /* Line to be drawn while displaying */
|
|
static BOOLEAN extraByteAdvance;
|
|
|
|
static unsigned linesAvailable;
|
|
|
|
/* Bytes to skip before or after doing raw drawing */
|
|
static unsigned long preSkip, postSkip;
|
|
|
|
/* Buffer to hold all SHR pixel data from one update (defined in tables.asm).
|
|
* Must be big enough: at least (WIN_WIDTH_640/4 + 1) * WIN_HEIGHT. */
|
|
#define DESTBUF_SIZE 0x8001
|
|
extern unsigned char destBuf[];
|
|
|
|
static unsigned char *destPtr;
|
|
|
|
unsigned char * rawDecode640(unsigned startOffset, unsigned endOffset,
|
|
unsigned char *lineDataPtr);
|
|
unsigned char * rawDecode320(unsigned startOffset, unsigned endOffset,
|
|
unsigned char *lineDataPtr);
|
|
|
|
|
|
/* Ends drawing of a raw rectangle when it is complete or aborted
|
|
* because the rectangle is not visible.
|
|
*/
|
|
static void StopRawDrawing (void) {
|
|
NextRect(); /* Prepare for next rect */
|
|
}
|
|
|
|
#pragma optimize 95 /* To work around an ORCA/C optimizer bug */
|
|
|
|
/* Draw one or more lines from a raw rectangle
|
|
*/
|
|
void RawDraw (void) {
|
|
static unsigned char *lineDataPtr;
|
|
unsigned int i; /* Loop indices */
|
|
unsigned char *initialLineDataPtr;
|
|
unsigned char *finalDestPtr;
|
|
static EventRecord eventRec;
|
|
unsigned long eventCheckTime;
|
|
|
|
/* For use with GetContentOrigin() */
|
|
Origin contentOrigin;
|
|
|
|
eventCheckTime = TickCount() + EVENT_CHECK_INVERVAL;
|
|
SetPort(vncWindow); /* Drawing in VNC window */
|
|
|
|
#if 0
|
|
/* Check if what we're drawing is visible, and skip any invisible part
|
|
* by skipping some lines or completely aborting drawing the rectangle.
|
|
*/
|
|
if (checkBounds) {
|
|
Rect drawingRect;
|
|
|
|
contentOrigin.l = GetContentOrigin(vncWindow);
|
|
drawingRect.h1 = rectX - contentOrigin.pt.h;
|
|
drawingRect.h2 = rectX - contentOrigin.pt.h + rectWidth;
|
|
drawingRect.v1 = rectY - contentOrigin.pt.v + drawingLine;
|
|
drawingRect.v2 = rectY - contentOrigin.pt.v + rectHeight;
|
|
|
|
if (!RectInRgn(&drawingRect, GetVisHandle())) {
|
|
StopRawDrawing();
|
|
return;
|
|
}
|
|
else if (rectY + drawingLine < contentOrigin.pt.v) {
|
|
unsigned linesToSkip = contentOrigin.pt.v - rectY - drawingLine;
|
|
preSkip = linesToSkip * rectWidth;
|
|
destPtr += (unsigned long)lineBytes * linesToSkip;
|
|
drawingLine = contentOrigin.pt.v - rectY;
|
|
|
|
if (drawingLine >= rectHeight) { /* Sanity check */
|
|
StopRawDrawing();
|
|
return;
|
|
}
|
|
}
|
|
else if (rectY + rectHeight - 1 > contentOrigin.pt.v + winHeight)
|
|
rectHeight = contentOrigin.pt.v + winHeight - rectY + 1;
|
|
|
|
checkBounds = FALSE;
|
|
}
|
|
#endif
|
|
|
|
do { /* We short-circuit back to here if there are no events pending */
|
|
unsigned inPixelsA, inPixelsB, outPixels;
|
|
|
|
if (linesAvailable == 0) {
|
|
linesAvailable = DoReadMultipleTCP(rectWidth, rectHeight - drawingLine);
|
|
if (linesAvailable) {
|
|
lineDataPtr = readBufferPtr;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
finalDestPtr = destPtr + lineBytes - 1;
|
|
if (hRez == 640) {
|
|
initialLineDataPtr = lineDataPtr;
|
|
lineDataPtr = rawDecode640(destPtr-destBuf, finalDestPtr-destBuf, lineDataPtr);
|
|
destPtr = finalDestPtr;
|
|
*destPtr = pixTransTbl[*(lineDataPtr++)] & 0xC0;
|
|
for (i = lineDataPtr - initialLineDataPtr; i < rectWidth; i++)
|
|
switch (i & 0x03) {
|
|
case 0x01: /* pixels 1, 5, 9, ... */
|
|
*destPtr += pixTransTbl[*(lineDataPtr++)] & 0x30;
|
|
break;
|
|
case 0x02: /* pixels 2, 6, 10, ... */
|
|
*destPtr += pixTransTbl[*(lineDataPtr++)] & 0x0C;
|
|
break;
|
|
case 0x03: /* pixels 3, 7, 11, ... */
|
|
*destPtr += pixTransTbl[*(lineDataPtr++)] & 0x03;
|
|
}
|
|
destPtr++;
|
|
}
|
|
else { /* 320 mode */
|
|
lineDataPtr = rawDecode320(destPtr-destBuf, finalDestPtr-destBuf, lineDataPtr);
|
|
destPtr = finalDestPtr;
|
|
/* Final byte to produce */
|
|
*destPtr = pixTransTbl[*(lineDataPtr++)] & 0xF0;
|
|
if (extraByteAdvance)
|
|
destPtr++; /* Not ending on byte boundary - update index */
|
|
else
|
|
*(destPtr++) += pixTransTbl[*(lineDataPtr++)] & 0x0F;
|
|
}
|
|
|
|
drawingLine++;
|
|
|
|
if (pixels > 613 && !(drawingLine & 0x03)) { /* Draw every 4th line */
|
|
srcRect.v2 = drawingLine;
|
|
contentOrigin.l = GetContentOrigin(vncWindow);
|
|
PPToPort(&srcLocInfo, &srcRect, rectX - contentOrigin.pt.h,
|
|
rectY + srcRect.v1 - contentOrigin.pt.v, modeCopy);
|
|
srcRect.v1 = drawingLine;
|
|
}
|
|
|
|
/* Check whether we're done with this rectangle */
|
|
if (drawingLine >= rectHeight) {
|
|
/* Draw final rect, if necessary */
|
|
if (drawingLine > srcRect.v1) {
|
|
srcRect.v2 = drawingLine;
|
|
contentOrigin.l = GetContentOrigin(vncWindow);
|
|
PPToPort(&srcLocInfo, &srcRect, rectX - contentOrigin.pt.h,
|
|
rectY + srcRect.v1 - contentOrigin.pt.v, modeCopy);
|
|
}
|
|
StopRawDrawing();
|
|
return;
|
|
}
|
|
|
|
linesAvailable--;
|
|
|
|
/* Check if there are actually any events that need to be processed.
|
|
* If not, save time by not going through the whole event loop, but
|
|
* instead processing the minimum necessary periodic tasks and then
|
|
* going straight to the next line of data.
|
|
*/
|
|
if (TickCount() >= eventCheckTime) {
|
|
if (EventAvail(0xFFFF, &eventRec))
|
|
return;
|
|
SystemTask(); /* Let periodic Desk Accesories do their things */
|
|
eventCheckTime = eventRec.when + EVENT_CHECK_INVERVAL;
|
|
}
|
|
TCPIPPoll(); /* Let Marinetti keep processing data */
|
|
} while (1);
|
|
}
|
|
|
|
#pragma optimize -1
|
|
|
|
/* Process rectangle data in raw encoding and write it to screen.
|
|
*/
|
|
void DoRawRect (void) {
|
|
pixels = (unsigned long) rectWidth * rectHeight;
|
|
|
|
if (hRez == 640) {
|
|
if (rectWidth & 0x03) { /* Width not an exact multiple of 4 */
|
|
lineBytes = rectWidth/4 + 1;
|
|
}
|
|
else { /* Width is a multiple of 4 */
|
|
lineBytes = rectWidth/4;
|
|
}
|
|
}
|
|
else { /* 320 mode */
|
|
if (rectWidth & 0x01) { /* Width not an exact multiple of 2 */
|
|
lineBytes = rectWidth/2 + 1;
|
|
extraByteAdvance = TRUE;
|
|
}
|
|
else { /* Width is a multiple of 2 */
|
|
lineBytes = rectWidth/2;
|
|
extraByteAdvance = FALSE;
|
|
}
|
|
}
|
|
|
|
/* If we get an oversized update, ignore it and ask for another one.
|
|
* Shouldn't normally happen, except possibly if there are outstanding
|
|
* update requests for multiple screen regions due to scrolling.
|
|
*/
|
|
if (lineBytes * rectHeight >= DESTBUF_SIZE) {
|
|
Origin contentOrigin;
|
|
|
|
contentOrigin.l = GetContentOrigin(vncWindow);
|
|
SendFBUpdateRequest(FALSE, contentOrigin.pt.h, contentOrigin.pt.v,
|
|
winWidth, winHeight);
|
|
skipBytes = pixels;
|
|
StopRawDrawing();
|
|
return;
|
|
}
|
|
destPtr = destBuf;
|
|
|
|
srcLocInfo.ptrToPixImage = destPtr;
|
|
srcLocInfo.width = lineBytes;
|
|
srcLocInfo.boundsRect.v2 = rectHeight;
|
|
/* Since the lines are rounded up to integral numbers of bytes, this
|
|
* padding must be accounted for here.
|
|
*/
|
|
if (hRez == 640) {
|
|
switch (rectWidth & 0x03) {
|
|
case 0x00: srcLocInfo.boundsRect.h2 = rectWidth; break;
|
|
case 0x01: srcLocInfo.boundsRect.h2 = rectWidth+3; break;
|
|
case 0x02: srcLocInfo.boundsRect.h2 = rectWidth+2; break;
|
|
case 0x03: srcLocInfo.boundsRect.h2 = rectWidth+1;
|
|
}
|
|
}
|
|
else {
|
|
switch (rectWidth & 0x01) {
|
|
case 0x00: srcLocInfo.boundsRect.h2 = rectWidth; break;
|
|
case 0x01: srcLocInfo.boundsRect.h2 = rectWidth+1;
|
|
}
|
|
}
|
|
|
|
/* Don't include padding in the area we will actually copy over */
|
|
srcRect.h2 = rectWidth;
|
|
srcRect.v1 = 0;
|
|
|
|
displayInProgress = TRUE;
|
|
drawingLine = 0; /* Drawing first line of rect */
|
|
linesAvailable = 0; /* No line data read yet */
|
|
checkBounds = TRUE; /* Flag to check bounds when drawing 1st line */
|
|
}
|