diff options
Diffstat (limited to 'nxcompshad/src/Core.cpp')
-rw-r--r-- | nxcompshad/src/Core.cpp | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/nxcompshad/src/Core.cpp b/nxcompshad/src/Core.cpp new file mode 100644 index 000000000..2b2163ea1 --- /dev/null +++ b/nxcompshad/src/Core.cpp @@ -0,0 +1,626 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMPSHAD, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <sys/time.h> + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include "Core.h" +#include "Logger.h" + +const int CorePoller::maxSliceHeight_ = 20; +const int CorePoller::minSliceHeight_ = 3; + +const char CorePoller::interlace_[] = +{ + 0, 16, + 8, 24, + 4, 20, 12, 28, + 2, 18, 10, 26, 6, 22, 14, 30, + 1, 17, + 9, 25, + 5, 21, 13, 29, + 3, 19, 11, 27, 7, 23, 15, 31 +}; + +CorePoller::CorePoller(Input *input, Display *display) : input_(input) +{ + logTrace("CorePoller::CorePoller"); + + buffer_ = NULL; + lastUpdatedRegion_ = NULL; + lineStatus_ = NULL; + linePriority_ = NULL; + lefts_ = NULL; + rights_ = NULL; +} + +CorePoller::~CorePoller() +{ + logTrace("CorePoller::~CorePoller"); + + if (buffer_ != NULL) + { + delete [] buffer_; + + buffer_ = NULL; + } + + if (lastUpdatedRegion_ != NULL) + { + XDestroyRegion(lastUpdatedRegion_); + + lastUpdatedRegion_ = NULL; + } + + if (lineStatus_ != NULL) + { + delete [] lineStatus_; + + lineStatus_ = NULL; + } + + if (linePriority_ != NULL) + { + delete [] linePriority_; + + linePriority_ = NULL; + } + + if (lefts_ != NULL) + { + delete [] lefts_; + + lefts_ = NULL; + } + + if (rights_ != NULL) + { + delete [] rights_; + + rights_ = NULL; + } +} + +int CorePoller::init() +{ + logTrace("CorePoller::init"); + + createFrameBuffer(); + + if (buffer_ == NULL) + { + logError("CorePoller::init", ESET(ENOMEM)); + + return -1; + } + + logTest("CorePoller::init", "Allocated frame buffer at [%p] for [%d] bytes.", + buffer_, bpl_ * height_); + + if (lastUpdatedRegion_ != NULL) + { + XDestroyRegion(lastUpdatedRegion_); + + lastUpdatedRegion_ = NULL; + } + + lastUpdatedRegion_ = XCreateRegion(); + + if (lineStatus_ != NULL) + { + delete[] lineStatus_; + } + + lineStatus_ = new LineStatus[height_ + 1]; + + if (lineStatus_ == NULL) + { + logError("CorePoller::init", ESET(ENOMEM)); + + return -1; + } + + // + // We need this boundary element to + // speed up the algo. + // + + if (linePriority_ != NULL) + { + delete[] linePriority_; + } + + linePriority_ = new int [height_ + 1]; + + if (linePriority_ == NULL) + { + logError("CorePoller::init", ESET(ENOMEM)); + + return -1; + } + + for (unsigned int i = 0; i < height_; i++) + { + linePriority_[i] = HIGHEST_PRIORITY; + } + + if (lefts_ != NULL) + { + delete[] lefts_; + } + + lefts_ = new int [height_]; + + if (rights_ != NULL) + { + delete[] rights_; + } + + rights_ = new int [height_]; + + for (unsigned int i = 0; i < height_; i++) + { + rights_[i] = lefts_[i] = 0; + } + + return 1; +} + +int CorePoller::isChanged(int (*checkIfInputCallback)(void *), void *arg, int *suspended) +{ + logTrace("CorePoller::isChanged"); + +#if defined(__CYGWIN32__) || defined(WIN32) + + checkDesktop(); + +#endif + +#if !defined(__CYGWIN32__) && !defined(WIN32) + + if (mirror_ == 1) + { + int result = mirrorChanges_; + + mirrorChanges_ = 0; + + return result; + } + +#endif + + logDebug("CorePoller:isChanged", "Going to use default polling algorithm.\n"); + + // + // In order to allow this function to + // be suspended and resumed later, we + // need to save these two status vars. + // + + static int idxIlace = 0; + static int curLine = 0; + + + const long timeout = 50; + long oldTime; + long newTime; + struct timeval ts; + + gettimeofday(&ts, NULL); + + oldTime = ts.tv_sec * 1000 + ts.tv_usec / 1000; + + if (curLine == 0) // && idxIlace == 0 ? + { + for (unsigned int i = 0; i < height_; i++) + { + lineStatus_[i] = LINE_NOT_CHECKED; + } + } + + int foundChanges = 0; + + foundChanges = 0; + + int curIlace = interlace_[idxIlace]; + + bool moveBackward = false; + + logDebug("CorePoller::isChanged", "Interlace index [%d] interlace [%d].", idxIlace, curIlace); + + for (; curLine < (int) height_; curLine++) + { + logDebug("CorePoller::isChanged", "Analizing line [%d] move backward [%d] status [%d] priority [%d].", + curLine, moveBackward, lineStatus_[curIlace], linePriority_[curLine]); + + // + // Ask the caller if the polling have to be suspended. + // + + if ((*checkIfInputCallback)(arg) == 1) + { + *suspended = 1; + + break; + } + + // + // Suspend if too much time is elapsed. + // + + gettimeofday(&ts, NULL); + + newTime = ts.tv_sec * 1000 + ts.tv_usec / 1000; + + if (newTime - oldTime >= timeout) + { + *suspended = 1; + + break; + } + + oldTime = newTime; + + if (lineStatus_[curLine] != LINE_NOT_CHECKED) + { + continue; + } + + if (moveBackward) + { + moveBackward = false; + } + else + { + switch (linePriority_[curLine]) + { + case 1: + case 29: + { + // + // It was a priority, + // but now it may not be. + // + } + case 31: + { + // + // Not a priority, still isn't. + // + + linePriority_[curLine] = NOT_PRIORITY; + + break; + } + case 0: + { + // + // Make it a priority. + // + + linePriority_[curLine] = PRIORITY; + + break; + } + default: + { + linePriority_[curLine]--; + + break; + } + } + + if ((linePriority_[curLine] > PRIORITY) && ((curLine & 31) != curIlace)) + { + continue; + } + } + + XRectangle rect = {0, curLine, width_, 1}; + + char *buffer; + + logDebug("CorePoller::isChanged", "Checking line [%d].", curLine); + + if ((buffer = getRect(rect)) == NULL) + { + logDebug("CorePoller::isChanged", "Failed to retrieve line [%d].", curLine); + + return -1; + } + + if (memcmp(buffer, buffer_ + curLine * bpl_, bpl_) == 0 || differ(buffer, rect) == 0) + { + logDebug("CorePoller::isChanged", "Data buffer didn't change."); + + lineStatus_[curLine] = LINE_NOT_CHANGED; + + continue; + } + + rect.x = lefts_[rect.y]; + rect.width = rights_[rect.y] - lefts_[rect.y] + 1; + + update(buffer + rect.x * bpp_, rect); + + foundChanges = 1; + + lineStatus_[curLine] = LINE_HAS_CHANGED; + + // + // Wake up the next line. + // + + if (linePriority_[curLine + 1] > PRIORITY) + { + linePriority_[curLine + 1] = HIGHEST_PRIORITY; + } + + // + // Give this line priority. + // + + linePriority_[curLine] = HIGHEST_PRIORITY; + + // + // Wake up previous line. + // + + if (curLine > 0 && lineStatus_[curLine - 1] == LINE_NOT_CHECKED) + { + moveBackward = true; + curLine -= 2; + } + } + + // + // Execution reached the end of loop. + // + + if (curLine == (int) height_) + { + idxIlace = (idxIlace + 1) % 32; + + curLine = 0; + } + + // + // Create the region of changed pixels. + // + + if (foundChanges) + { + int start, last, curWorkLine, left, right; + + for (curWorkLine = 0; curWorkLine < (int) height_; curWorkLine++) + { + if (lineStatus_[curWorkLine] == LINE_HAS_CHANGED) + { + break; + } + } + + start = curWorkLine; + last = curWorkLine; + + left = lefts_[curWorkLine]; + right = rights_[curWorkLine]; + curWorkLine++; + + while (1) + { + for (; curWorkLine < (int) height_; curWorkLine++) + { + if (lineStatus_[curWorkLine] == LINE_HAS_CHANGED) + { + break; + } + } + + if (curWorkLine == (int) height_) + { + break; + } + + if ((curWorkLine - last > minSliceHeight_) || (last - start > maxSliceHeight_)) + { + XRectangle rect = {left, start, right - left + 1, last - start + 1}; + + XUnionRectWithRegion(&rect, lastUpdatedRegion_, lastUpdatedRegion_); + + start = curWorkLine; + left = lefts_[curWorkLine]; + right = rights_[curWorkLine]; + } + else + { + if (lefts_[curWorkLine] < left) + { + left = lefts_[curWorkLine]; + } + + if (rights_[curWorkLine] > right) + { + right = rights_[curWorkLine]; + } + } + + last = curWorkLine; + + curWorkLine++; + } + + // + // Send last block. + // + + if (last >= start) + { + XRectangle rect = {left, start, right - left + 1, last - start + 1}; + + XUnionRectWithRegion(&rect, lastUpdatedRegion_, lastUpdatedRegion_); + } + } + + return foundChanges; +} + +int CorePoller::differ(char *buffer, XRectangle r) +{ + logTrace("CorePoller::differ"); + + int bpl = bpp_ * r.width; + int i; + char *pBuf; + char *pFb; + + pBuf = (buffer); + pFb = (buffer_ + r.x + r.y * bpl_); + + for (i = 0; i < bpl; i++) + { + if (*pFb++ != *pBuf++) + { + lefts_[r.y] = i / bpp_; + + break; + } + } + + if (i == bpl) + { + return 0; + } + + pBuf = (buffer) + bpl - 1; + pFb = (buffer_ + r.x + r.y * bpl_) + bpl - 1; + + int j = i - 1; + + for (i = bpl - 1; i > j; i--) + { + if (*pFb-- != *pBuf--) + { + rights_[r.y] = i / bpp_; + + break; + } + } + + return 1; +} + +void CorePoller::update(char *src, XRectangle r) +{ + logTrace("CorePoller::update"); + + char *dst = buffer_ + r.x * bpp_ + r.y * bpl_; + int bpl = bpp_ * r.width; + + for (unsigned int i = 0; i < r.height; i++) + { + if(((r.x * bpp_ + r.y * bpl_) + bpl) > (bpl_ * height_)) + { + // + // Out of bounds. Maybe a resize is going on. + // + + continue; + } + + memcpy(dst, src, bpl); + + src += bpl; + + dst += bpl_; + } +} + +void CorePoller::handleEvent(Display *display, XEvent *event) +{ + logTrace("CorePoller::handleEvent"); + + switch (event -> type) + { + case KeyPress: + case KeyRelease: + { + handleKeyboardEvent(display, event); + break; + } + case ButtonPress: + case ButtonRelease: + case MotionNotify: + { + handleMouseEvent(display, event); + break; + } + default: + { + logTest("CorePoller::handleEvent", "Handling unexpected event [%d] from display [%p].", + event -> type, display); + break; + } + } +} + +void CorePoller::handleWebKeyEvent(KeySym keysym, Bool isKeyPress) +{ + logTrace("CorePoller::handleWebKeyEvent"); + + handleWebKeyboardEvent(keysym, isKeyPress); +} + +void CorePoller::handleInput() +{ + while (input_ -> checkIfEvent()) + { + Display *display = input_ -> currentDisplay(); + XEvent *event = input_ -> popEvent(); + + handleEvent(display, event); + + delete event; + } +} + +void CorePoller::createFrameBuffer() +{ + logTrace("CorePoller::createFrameBuffer"); + + if (buffer_ == NULL) + { + buffer_ = new char[bpl_ * height_]; + } +} |