#if __ORCAC__ #pragma lint -1 #pragma noroot segment "VNCview GS"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vncsession.h" #include "vncview.h" #include "vncdisplay.h" #include "colortables.h" #include "readtcp.h" #include "menus.h" #include "clipboard.h" #include "desktopsize.h" #include "mouse.h" #include "keyboard.h" #include "copyrect.h" #include "raw.h" #include "hextile.h" unsigned int fbHeight; unsigned int fbWidth; BOOLEAN displayInProgress; static BOOLEAN peekedNextMsg; static unsigned int numRects; unsigned int rectX; unsigned int rectY; unsigned int rectWidth; unsigned int rectHeight; static unsigned long rectEncoding; GrafPortPtr vncWindow; /* VNC session window dimensions */ unsigned int winHeight; unsigned int winWidth; /* On the next 2 structs, only certain values are permanently zero. * Others are changed later. */ struct LocInfo srcLocInfo = {0, 0, 0, {0, 0, 0, 0} }; /* Used by multiple encodings */ Rect srcRect = {0, 0, 0, 0}; unsigned char *pixTransTbl; BOOLEAN checkBounds = FALSE; /* Adjust drawing to stay in bounds */ unsigned long skipBytes = 0; /* Server-to-client message types */ #define FBUpdate 0 #define SetColourMapEntries 1 #define Bell 2 #define ServerCutText 3 #define txtColor 10 #define txtGray 11 #define txtTransfers 23 /* Send a request to be sent the data to redraw the window when part of it has * been erased. It will be a while before the data is fully redrawn, but this * is an unavoidable penalty of opening other windows over the main VNC window. */ #pragma databank 1 static void VNCRedraw (void) { RegionHndl updateRgnHndl; updateRgnHndl = vncWindow->visRgn; SendFBUpdateRequest(FALSE, (**updateRgnHndl).rgnBBox.h1, (**updateRgnHndl).rgnBBox.v1, (**updateRgnHndl).rgnBBox.h2 - (**updateRgnHndl).rgnBBox.h1, (**updateRgnHndl).rgnBBox.v2 - (**updateRgnHndl).rgnBBox.v1); checkBounds = TRUE; } #pragma databank 0 /* Change Super Hi-Res display to the specified resolution (640 or 320). * Uses the procedure described in IIgs Tech Note #4. */ static void ChangeResolution(int rez) { static Handle dpSpace; unsigned int masterSCB; hRez = rez; winHeight = WIN_HEIGHT; winWidth = (rez == 640) ? WIN_WIDTH_640 : WIN_WIDTH_320; /* Set up pixel translation table for correct graphics mode */ if (rez == 320) pixTransTbl = coltab320; else /* 640 mode */ pixTransTbl = coltab640; srcLocInfo.portSCB = (rez == 640) ? 0x87 : 0x00; /* Check if we need to change modes */ masterSCB = GetMasterSCB(); if ( ( (masterSCB & 0x80) && (rez == 640)) || (!(masterSCB & 0x80) && (rez == 320)) ) { return; /* Already in right mode, so don't change things */ } /* Perform the basic procedure described in IIgs TN #4, * with some adjustments to provide a smoother transition. */ CloseAllNDAs(); QDAuxShutDown(); SetMasterSCB(masterSCB | 0x100); /* To leave SHR screen active */ QDShutDown(); if (dpSpace == NULL) dpSpace = NewHandle(0x0300, userid(), attrLocked|attrFixed|attrNoCross|attrBank, 0x00000000); QDStartUp((Word) *dpSpace, (rez == 640) ? 0xC187 : 0xC100, 0, userid()); /* SCB 0x87 gives 640 mode with our custom gray palette */ QDAuxStartUp(); ClampMouse(0, (rez == 640) ? 639 : 319, 0, 199); HomeMouse(); ShowCursor(); WindNewRes(); InitPalette(); /* Set up Apple menu colors before it is redrawn */ MenuNewRes(); CtlNewRes(); RefreshDesktop(NULL); /* Position new connection window at default location for new mode */ if (rez == 320) { MoveControl(25, 64, GetCtlHandleFromID(newConnWindow, txtColor)); MoveControl(25, 87, GetCtlHandleFromID(newConnWindow, txtGray)); MoveControl(134, 91, GetCtlHandleFromID(newConnWindow, txtTransfers)); MoveWindow(2, 35, newConnWindow); } else { MoveControl(35, 64, GetCtlHandleFromID(newConnWindow, txtColor)); MoveControl(35, 87, GetCtlHandleFromID(newConnWindow, txtGray)); MoveControl(144, 91, GetCtlHandleFromID(newConnWindow, txtTransfers)); MoveWindow(162, 35, newConnWindow); } } /* Display the VNC session window, first changing to the appropriate * resolution (as specified by the user) if necessary. */ void InitVNCWindow(void) { #define wrNum640 1003 #define wrNum320 1004 BOOLEAN resize = FALSE; ChangeResolution(hRez); vncWindow = NewWindow2(NULL, 0, NULL, NULL, 0x02, (hRez == 640) ? wrNum640 : wrNum320, rWindParam1); if (fbWidth < winWidth) { winWidth = fbWidth; resize = TRUE; } if (fbHeight < winHeight) { winHeight = fbHeight; resize = TRUE; } if (resize) SizeWindow(winWidth, winHeight, vncWindow); SetContentDraw(VNCRedraw, vncWindow); SetDataSize(fbWidth, fbHeight, vncWindow); DrawControls(vncWindow); /* We also take the opportunity here to initialize the rectangle info. */ numRects = 0; displayInProgress = FALSE; peekedNextMsg = FALSE; #undef wrNum320 #undef wrNum640 } /* Send a request to the VNC server to update the information for a portion of * the frame buffer. */ void SendFBUpdateRequest (BOOLEAN incremental, unsigned int x, unsigned int y, unsigned int width, unsigned int height) { struct FBUpdateRequest { unsigned char messageType; unsigned char incremental; unsigned int x; unsigned int y; unsigned int width; unsigned int height; } fbUpdateRequest = {3 /* Message type 3 */}; fbUpdateRequest.incremental = !!incremental; fbUpdateRequest.x = SwapBytes2(x); fbUpdateRequest.y = SwapBytes2(y); fbUpdateRequest.width = SwapBytes2(width); fbUpdateRequest.height = SwapBytes2(height); TCPIPWriteTCP(hostIpid, &fbUpdateRequest.messageType, sizeof(fbUpdateRequest), TRUE, FALSE); /* No error checking here -- Can't respond to one usefully. */ } /* Start responding to a FramebufferUpdate from the server */ static void DoFBUpdate (void) { unsigned int *dataPtr; /* Pointer to header data */ if (!DoWaitingReadTCP(15)) { DoClose(vncWindow); //printf("Closing in DoFBUpdate\n"); return; } dataPtr = (unsigned int *) (readBufferPtr + 1); numRects = SwapBytes2(dataPtr[0]); /* Get data */ rectX = SwapBytes2(dataPtr[1]); rectY = SwapBytes2(dataPtr[2]); rectWidth = SwapBytes2(dataPtr[3]); rectHeight = SwapBytes2(dataPtr[4]); rectEncoding = SwapBytes4(*(unsigned long *)(dataPtr + 5)); } /* The server should never send a color map, since we don't use a mapped * representation for pixel values. If a malfunctioning server tries to * send us one, though, we read and ignore it. */ static void DoSetColourMapEntries (void) { unsigned int numColors; DoWaitingReadTCP(3); DoWaitingReadTCP(2); numColors = SwapBytes2(*(unsigned int *)readBufferPtr); skipBytes = 6UL * numColors; } /* Skip a specified number of bytes. */ static void DoSkipBytes (void) { if (DoReadTCP(skipBytes)) { DoneWithReadBuffer(); skipBytes = 0; } } /* Here when we're done processing one rectangle and ready to start the next. * If last FramebufferUpdate had multiple rectangles, we set up for next one. * If no more rectangles are available, we send a FramebufferUpdateRequest. */ void NextRect (void) { unsigned int *dataPtr; displayInProgress = FALSE; numRects--; if (numRects) { /* Process next rectangle */ if (!DoWaitingReadTCP(12)) { //printf("Closing in NextRect\n"); DoClose(vncWindow); return; } dataPtr = (unsigned int *)readBufferPtr; rectX = SwapBytes2(dataPtr[0]); rectY = SwapBytes2(dataPtr[1]); rectWidth = SwapBytes2(dataPtr[2]); rectHeight = SwapBytes2(dataPtr[3]); rectEncoding = SwapBytes4(*(unsigned long *)(dataPtr + 4)); //printf("New Rect: X = %u, Y = %u, Width = %u, Height = %u\n", rectX, rectY, rectWidth, rectHeight); } else { /* No more rectangles from last update */ Origin contentOrigin; DoneWithReadBuffer(); if (DoReadTCP(1)) { peekedNextMsg = TRUE; if (*readBufferPtr == FBUpdate) { /* Don't request another FBUpdate if one is already coming. * This helps avoid a condition where the GS may be unable * to "catch up" with a stream of frequent updates. */ return; } } contentOrigin.l = GetContentOrigin(vncWindow); SendFBUpdateRequest(TRUE, contentOrigin.pt.h, contentOrigin.pt.v, winWidth, winHeight); } } void ConnectedEventLoop (void) { unsigned char messageType; if (FrontWindow() != vncWindow && menuOffset == noKB) InitMenus(0); else if (FrontWindow() == vncWindow && menuOffset != noKB) InitMenus(noKB); if (skipBytes) { DoSkipBytes(); return; } else if (displayInProgress) { switch (rectEncoding) { case encodingRaw: RawDraw(); return; case encodingHextile: HexDispatch(); return; case nonEncodingClipboard: GetClipboard(); return; default: DoClose(vncWindow); return; } } else if (numRects) { switch (rectEncoding) { case encodingHextile: DoHextileRect(); return; case encodingRaw: DoRawRect(); return; case encodingCopyRect: DoCopyRect(); return; case encodingDesktopSize: DoDesktopSize(); return; case encodingCursor: DoCursor(); return; default: DisplayConnectStatus ( "\pInvalid rectangle from server.", FALSE); DoClose(vncWindow); //printf("Closing due to bad rectangle encoding %lu\n", rectEncoding); //printf("rectX = %u, rectY = %u, rectWidth = %u, rectHeight = %u\n", rectX, rectY, rectWidth, rectHeight); return; } } else if (peekedNextMsg || DoReadTCP(1)) { /* Read message type byte */ peekedNextMsg = FALSE; messageType = *readBufferPtr; switch (messageType) { case FBUpdate: DoFBUpdate(); break; case SetColourMapEntries: DoSetColourMapEntries(); break; case Bell: SysBeep(); break; case ServerCutText: rectEncoding = nonEncodingClipboard; DoServerCutText(); break; default: DisplayConnectStatus ( "\pInvalid message from server.", FALSE); DoClose(vncWindow); return; } } }