aboutsummaryrefslogtreecommitdiff
path: root/nxcompshad/src
diff options
context:
space:
mode:
authorMike Gabriel <mike.gabriel@das-netzwerkteam.de>2017-04-25 15:27:17 +0200
committerMike Gabriel <mike.gabriel@das-netzwerkteam.de>2017-07-13 11:38:42 +0200
commit76b48676844bc7aa0511b8371ef6347b2e8ad545 (patch)
tree6c81a895407116ca2e3f1522c81e5d1d7122fd01 /nxcompshad/src
parent622360ea2ec9cde354aece445e4b9fb4b7664eea (diff)
downloadnx-libs-76b48676844bc7aa0511b8371ef6347b2e8ad545.tar.gz
nx-libs-76b48676844bc7aa0511b8371ef6347b2e8ad545.tar.bz2
nx-libs-76b48676844bc7aa0511b8371ef6347b2e8ad545.zip
nxcompshad: Switch to autoreconf.
Diffstat (limited to 'nxcompshad/src')
-rw-r--r--nxcompshad/src/Core.cpp626
-rw-r--r--nxcompshad/src/Core.h212
-rw-r--r--nxcompshad/src/Input.cpp179
-rw-r--r--nxcompshad/src/Input.h99
-rw-r--r--nxcompshad/src/Logger.cpp128
-rw-r--r--nxcompshad/src/Logger.h167
-rw-r--r--nxcompshad/src/Makefile.am45
-rw-r--r--nxcompshad/src/Manager.cpp264
-rw-r--r--nxcompshad/src/Manager.h123
-rw-r--r--nxcompshad/src/Misc.h50
-rw-r--r--nxcompshad/src/Poller.h39
-rw-r--r--nxcompshad/src/Regions.h43
-rw-r--r--nxcompshad/src/Shadow.cpp482
-rw-r--r--nxcompshad/src/Updater.cpp395
-rw-r--r--nxcompshad/src/Updater.h103
-rw-r--r--nxcompshad/src/Win.cpp1149
-rw-r--r--nxcompshad/src/Win.h232
-rw-r--r--nxcompshad/src/X11.cpp1598
-rw-r--r--nxcompshad/src/X11.h139
-rw-r--r--nxcompshad/src/X11/include/XTest_nxcompshad.h71
-rw-r--r--nxcompshad/src/X11/include/Xdamage_nxcompshad.h92
-rw-r--r--nxcompshad/src/X11/include/Xrandr_nxcompshad.h80
22 files changed, 6316 insertions, 0 deletions
diff --git a/nxcompshad/src/Core.cpp b/nxcompshad/src/Core.cpp
new file mode 100644
index 000000000..de5f9a897
--- /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, curLine, left, right;
+
+ for (curLine = 0; curLine < (int) height_; curLine++)
+ {
+ if (lineStatus_[curLine] == LINE_HAS_CHANGED)
+ {
+ break;
+ }
+ }
+
+ start = curLine;
+ last = curLine;
+
+ left = lefts_[curLine];
+ right = rights_[curLine];
+ curLine++;
+
+ while (1)
+ {
+ for (; curLine < (int) height_; curLine++)
+ {
+ if (lineStatus_[curLine] == LINE_HAS_CHANGED)
+ {
+ break;
+ }
+ }
+
+ if (curLine == (int) height_)
+ {
+ break;
+ }
+
+ if ((curLine - last > minSliceHeight_) || (last - start > maxSliceHeight_))
+ {
+ XRectangle rect = {left, start, right - left + 1, last - start + 1};
+
+ XUnionRectWithRegion(&rect, lastUpdatedRegion_, lastUpdatedRegion_);
+
+ start = curLine;
+ left = lefts_[curLine];
+ right = rights_[curLine];
+ }
+ else
+ {
+ if (lefts_[curLine] < left)
+ {
+ left = lefts_[curLine];
+ }
+
+ if (rights_[curLine] > right)
+ {
+ right = rights_[curLine];
+ }
+ }
+
+ last = curLine;
+
+ curLine++;
+ }
+
+ //
+ // 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_];
+ }
+}
diff --git a/nxcompshad/src/Core.h b/nxcompshad/src/Core.h
new file mode 100644
index 000000000..91f3f1e22
--- /dev/null
+++ b/nxcompshad/src/Core.h
@@ -0,0 +1,212 @@
+/**************************************************************************/
+/* */
+/* 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. */
+/* */
+/**************************************************************************/
+
+#ifndef CorePoller_H
+#define CorePoller_H
+
+#include <stdio.h>
+
+#include "Logger.h"
+#include "Regions.h"
+#include "Input.h"
+
+typedef enum{
+ LINE_HAS_CHANGED,
+ LINE_NOT_CHECKED,
+ LINE_NOT_CHANGED
+} LineStatus;
+
+typedef enum{
+ HIGHEST_PRIORITY = 0,
+ PRIORITY = 30,
+ NOT_PRIORITY = 90
+} LinePriority;
+
+class CorePoller
+{
+ public:
+
+ CorePoller(Input*, Display*);
+
+ virtual ~CorePoller();
+
+ virtual int init();
+
+ unsigned int width() const;
+
+ unsigned int height() const;
+
+ unsigned char depth() const;
+
+ int isChanged(int (*)(void*), void *, int *);
+
+ char *getFrameBuffer() const;
+
+ void destroyFrameBuffer();
+
+ void createFrameBuffer();
+
+ Region lastUpdatedRegion();
+
+ Region getLastUpdatedRegion();
+
+ void handleInput();
+
+ void handleEvent(Display *, XEvent *);
+
+ void handleWebKeyEvent(KeySym keysym, Bool isKeyPress);
+
+ Display *getShadowDisplay();
+
+ void setShadowDisplay(Display *shadowDisplay);
+
+ protected:
+
+ unsigned int bpp_;
+
+ unsigned int bpl_;
+
+ unsigned int width_;
+
+ unsigned int height_;
+
+ int depth_;
+
+ char *buffer_;
+
+ unsigned long redMask_;
+ unsigned long greenMask_;
+ unsigned long blueMask_;
+ unsigned long colorMask_[3];
+
+ char mirror_;
+
+ char mirrorChanges_;
+
+ virtual int updateShadowFrameBuffer(void) = 0;
+
+ virtual char *getRect(XRectangle r) = 0;
+
+ int imageByteOrder_;
+
+ #ifdef __CYGWIN32__
+ virtual char checkDesktop(void) = 0;
+ #endif
+
+ Display *shadowDisplay_;
+
+ void update(char *src, XRectangle r);
+
+ Region lastUpdatedRegion_;
+
+ private:
+
+ virtual void handleKeyboardEvent(Display *, XEvent *) = 0;
+
+ virtual void handleWebKeyboardEvent(KeySym keysym, Bool isKeyPress) = 0;
+
+ virtual void handleMouseEvent(Display *, XEvent *) = 0;
+
+ Input *input_;
+
+ static const int maxSliceHeight_;
+ static const int minSliceHeight_;
+
+ LineStatus *lineStatus_;
+ int *linePriority_;
+
+ static const char interlace_[];
+
+ int *lefts_;
+ int *rights_;
+
+ // FIXME: Make them friend.
+
+ int differ(char *src, XRectangle r);
+};
+
+inline unsigned int CorePoller::width() const
+{
+ return width_;
+}
+
+inline unsigned int CorePoller::height() const
+{
+ return height_;
+}
+
+inline unsigned char CorePoller::depth() const
+{
+ return depth_;
+}
+
+inline char *CorePoller::getFrameBuffer() const
+{
+ return buffer_;
+}
+
+inline void CorePoller::destroyFrameBuffer()
+{
+ if (buffer_ != NULL)
+ {
+ delete[] buffer_;
+ buffer_ = NULL;
+ }
+}
+
+inline Region CorePoller::lastUpdatedRegion()
+{
+ Region region = lastUpdatedRegion_;
+
+ lastUpdatedRegion_ = XCreateRegion();
+
+ if (lastUpdatedRegion_ == NULL)
+ {
+ logError("CorePoller::lastUpdatedRegion", ESET(ENOMEM));
+
+ lastUpdatedRegion_ = region;
+
+ return NULL;
+ }
+
+ return region;
+}
+
+inline Region CorePoller::getLastUpdatedRegion()
+{
+ return lastUpdatedRegion_;
+}
+
+inline Display *CorePoller::getShadowDisplay()
+{
+ return shadowDisplay_ ;
+}
+
+inline void CorePoller::setShadowDisplay(Display *shadowDisplay)
+{
+ shadowDisplay_ = shadowDisplay;
+}
+
+#endif /* CorePoller_H */
diff --git a/nxcompshad/src/Input.cpp b/nxcompshad/src/Input.cpp
new file mode 100644
index 000000000..8de74c3c3
--- /dev/null
+++ b/nxcompshad/src/Input.cpp
@@ -0,0 +1,179 @@
+/**************************************************************************/
+/* */
+/* 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>
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+
+#include "Input.h"
+#include "Logger.h"
+
+Input::Input()
+{
+ logTrace("Input::Input");
+
+ eventsHead_ = NULL;
+ eventsTail_ = NULL;
+ keymap_ = NULL;
+}
+
+Input::~Input()
+{
+ logTrace("Input::~Input");
+
+ Event *head = eventsHead_;
+
+ while (head)
+ {
+ Event *next = head -> next;
+
+ delete head -> event;
+ delete head;
+
+ head = next;
+ }
+
+ if (keymap_ != NULL)
+ {
+ logDebug("Input::~Input", "Delete keymap_ [%p].", keymap_);
+
+ delete [] keymap_;
+ }
+}
+
+void Input::pushEvent(Display *display, XEvent *event)
+{
+ Event *tail = new Event;
+
+ if (tail == NULL)
+ {
+ logError("Input::pushEvent", ESET(ENOMEM));
+
+ return;
+ }
+
+ tail -> next = NULL;
+ tail -> display = display;
+ tail -> event = event;
+
+ if (eventsHead_ == NULL)
+ {
+ eventsHead_ = tail;
+ }
+ else
+ {
+ eventsTail_ -> next = tail;
+ }
+
+ eventsTail_ = tail;
+}
+
+XEvent *Input::popEvent()
+{
+ Event *head = eventsHead_;
+
+ if (head == NULL)
+ {
+ return 0;
+ }
+
+ XEvent *event = head -> event;
+
+ eventsHead_ = head -> next;
+
+ delete head;
+
+ if (eventsHead_ == NULL)
+ {
+ eventsTail_ = NULL;
+ }
+
+ return event;
+}
+
+int Input::removeAllEvents(Display *display)
+{
+ logTrace("Input::removeAllEvents");
+
+ int nRemoved = 0;
+
+ Event *current = eventsHead_;
+
+ while (current)
+ {
+ if (display == current -> display)
+ {
+ //
+ // Update head of list.
+ //
+
+ if (current == eventsHead_)
+ {
+ eventsHead_ = current -> next;
+ }
+
+ //
+ // Update tail of list.
+ //
+
+ if (current == eventsTail_)
+ {
+ eventsTail_ = eventsHead_;
+
+ while (eventsTail_ && eventsTail_ -> next)
+ {
+ eventsTail_ = eventsTail_ -> next;
+ }
+ }
+
+ //
+ // Remove event.
+ //
+
+ Event *next = current -> next;
+
+ delete current -> event;
+ delete current;
+
+ current = next;
+
+ nRemoved++;
+ }
+ else
+ {
+ current = current -> next;
+ }
+ }
+
+ return nRemoved;
+}
+
diff --git a/nxcompshad/src/Input.h b/nxcompshad/src/Input.h
new file mode 100644
index 000000000..cbba029a9
--- /dev/null
+++ b/nxcompshad/src/Input.h
@@ -0,0 +1,99 @@
+/**************************************************************************/
+/* */
+/* 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. */
+/* */
+/**************************************************************************/
+
+#ifndef Input_H
+#define Input_H
+
+#include <nx-X11/Xlib.h>
+
+typedef struct Event
+{
+ struct Event *next;
+ Display *display;
+ XEvent *event;
+} Event;
+
+class Input
+{
+ public:
+
+ Input();
+
+ ~Input();
+
+ int checkIfEvent();
+
+ void pushEvent(Display *, XEvent *);
+
+ XEvent *popEvent();
+ Display *currentDisplay();
+
+ int removeAllEvents(Display *);
+
+ void setKeymap(char *keymap);
+ char *getKeymap();
+
+ void setShadowDisplayName(char *shadowDisplayName);
+ char *getShadowDisplayName();
+
+ private:
+
+ Event *eventsHead_;
+ Event *eventsTail_;
+ char *keymap_;
+ char *shadowDisplayName_;
+};
+
+inline Display *Input::currentDisplay()
+{
+ return eventsHead_ ? eventsHead_ -> display : NULL;
+}
+
+inline int Input::checkIfEvent()
+{
+ return (eventsHead_ != NULL);
+}
+
+inline void Input::setKeymap(char *keymap)
+{
+ keymap_ = keymap;
+}
+
+inline char *Input::getKeymap()
+{
+ return keymap_;
+}
+
+inline void Input::setShadowDisplayName(char *shadowDisplayName)
+{
+ shadowDisplayName_ = shadowDisplayName;
+}
+
+inline char *Input::getShadowDisplayName()
+{
+ return shadowDisplayName_;
+}
+
+#endif /* Input_H */
diff --git a/nxcompshad/src/Logger.cpp b/nxcompshad/src/Logger.cpp
new file mode 100644
index 000000000..9648509b8
--- /dev/null
+++ b/nxcompshad/src/Logger.cpp
@@ -0,0 +1,128 @@
+/**************************************************************************/
+/* */
+/* 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 <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#define PANIC
+#define WARNING
+#undef TEST
+#define DEBUG
+
+#include "Misc.h"
+#include "Logger.h"
+
+Logger logger;
+
+void Logger::user(const char *format, va_list arguments)
+{
+ char string[1024];
+
+ vsnprintf(string, 1024, format, arguments);
+
+ fprintf(stderr, "%s\n", string);
+}
+
+void Logger::error(const char *name, int error)
+{
+ fprintf(stderr, "PANIC! %s: Failed with code %d: %s\n",
+ name, error, strerror(error));
+}
+
+void Logger::warning(const char *name, const char *format, va_list arguments)
+{
+ char string[1024];
+
+ vsnprintf(string, 1024, format, arguments);
+
+ fprintf(stderr, "%s: WARNING! %s\n", name, string);
+}
+
+void Logger::test(const char *name, const char *format, va_list arguments)
+{
+ char string[1024];
+
+ vsnprintf(string, 1024, format, arguments);
+
+ fprintf(stderr, "%s: %s\n", name, string);
+}
+
+void Logger::trace(const char *name)
+{
+ fprintf(stderr, "%s\n", name);
+}
+
+void Logger::debug(const char *name, const char *format, va_list arguments)
+{
+ char string[1024];
+
+ vsnprintf(string, 1024, format, arguments);
+
+ fprintf(stderr, "%s: %s\n", name, string);
+}
+
+void Logger::dump(const char *name, const char *data, int size)
+{
+ fprintf(stderr, "%s: Dumping %d bytes of data at %p\n",
+ name, size, data);
+
+ for (int i = 0; i < size;)
+ {
+ fprintf(stderr, "[%d]\t", i);
+
+ int t = i;
+
+ for (unsigned int ii = 0; i < size && ii < 8; i++, ii++)
+ {
+ fprintf(stderr, "%02x/%d\t", data[i] & 0xff, data[i]);
+ }
+
+ for (unsigned int ii = i % 8; ii > 0 && ii < 8; ii++)
+ {
+ fprintf(stderr, "\t");
+ }
+
+ i = t;
+
+ for (unsigned int ii = 0; i < size && ii < 8; i++, ii++)
+ {
+ if (isprint(data[i]))
+ {
+ fprintf(stderr, "%c", data[i]);
+ }
+ else
+ {
+ fprintf(stderr, ".");
+ }
+ }
+
+ fprintf(stderr, "\n");
+ }
+}
diff --git a/nxcompshad/src/Logger.h b/nxcompshad/src/Logger.h
new file mode 100644
index 000000000..eba81f642
--- /dev/null
+++ b/nxcompshad/src/Logger.h
@@ -0,0 +1,167 @@
+/**************************************************************************/
+/* */
+/* 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. */
+/* */
+/**************************************************************************/
+
+#ifndef Logger_H
+#define Logger_H
+
+#include <cerrno>
+#include <cstdarg>
+
+//
+// Error handling macros.
+//
+
+#define ESET(e) (errno = (e))
+#define EGET() (errno)
+#define ESTR() strerror(errno)
+
+extern class Logger logger;
+
+class Logger
+{
+ public:
+
+ void user(const char *format, va_list arguments);
+
+ void error(const char *name, int error);
+
+ void warning(const char *name, const char *format, va_list arguments);
+
+ void test(const char *name, const char *format, va_list arguments);
+
+ void trace(const char *name);
+
+ void debug(const char *name, const char *format, va_list arguments);
+
+ void dump(const char *name, const char *data, int size);
+};
+
+static inline void logUser(const char *format, ...) \
+ __attribute__((format(printf, 1, 2))) __attribute__((__unused__));
+
+static inline void logError(const char *name, int error) \
+ __attribute__((__unused__));
+
+static inline void logWarning(const char *name, const char *format, ...) \
+ __attribute__((__unused__));
+
+static inline void logTest(const char *name, const char *format, ...) \
+ __attribute__((format(printf, 2, 3))) __attribute__((__unused__));
+
+static inline void logTrace(const char *name) \
+ __attribute__((__unused__));
+
+static inline void logDebug(const char *name, const char *format, ...) \
+ __attribute__((format(printf, 2, 3))) __attribute__((__unused__));
+
+static inline void logDump(const char *name, const char *data, int size) \
+ __attribute__((__unused__));
+
+static inline void logUser(const char *format, ...)
+{
+ va_list arguments;
+
+ va_start(arguments, format);
+
+ logger.user(format, arguments);
+
+ va_end(arguments);
+}
+
+static inline void logError(const char *name, int error)
+{
+ #if defined(DEBUG) || defined(TEST) || \
+ defined(WARNING) || defined(PANIC)
+
+ logger.error(name, error);
+
+ #endif
+}
+
+static inline void logWarning(const char *name, const char *format, ...)
+{
+ #if defined(DEBUG) || defined(TEST) || \
+ defined(WARNING)
+
+ va_list arguments;
+
+ va_start(arguments, format);
+
+ logger.warning(name, format, arguments);
+
+ va_end(arguments);
+
+ #endif
+}
+
+static inline void logTest(const char *name, const char *format, ...)
+{
+ #if defined(TEST)
+
+ va_list arguments;
+
+ va_start(arguments, format);
+
+ logger.test(name, format, arguments);
+
+ va_end(arguments);
+
+ #endif
+}
+
+static inline void logTrace(const char *name)
+{
+ #if defined(DEBUG)
+
+ logger.trace(name);
+
+ #endif
+}
+
+static inline void logDebug(const char *name, const char *format, ...)
+{
+ #if defined(DEBUG)
+
+ va_list arguments;
+
+ va_start(arguments, format);
+
+ logger.debug(name, format, arguments);
+
+ va_end(arguments);
+
+ #endif
+}
+
+static inline void logDump(const char *name, const char *data, int size)
+{
+ #if defined(TEST)
+
+ logger.dump(name, data, size);
+
+ #endif
+}
+
+#endif /* Logger_H */
diff --git a/nxcompshad/src/Makefile.am b/nxcompshad/src/Makefile.am
new file mode 100644
index 000000000..c7f45ba27
--- /dev/null
+++ b/nxcompshad/src/Makefile.am
@@ -0,0 +1,45 @@
+NULL =
+
+lib_LTLIBRARIES = libXcompshad.la
+
+libXcompshad_la_SOURCES = \
+ Core.cpp \
+ Input.cpp \
+ Logger.cpp \
+ Manager.cpp \
+ Shadow.cpp \
+ Updater.cpp \
+ Win.cpp \
+ X11.cpp \
+ $(NULL)
+
+libXcompshad_la_LIBADD = \
+ @Xext_LIBS@ \
+ @Xdamage_LIBS@ \
+ @Xrandr_LIBS@ \
+ @Xtst_LIBS@ \
+ -L$(top_srcdir)/../nx-X11/exports/lib -lNX_X11 \
+ $(NULL)
+
+AM_CFLAGS = \
+ $(Xext_CFLAGS) \
+ $(Xdamage_CFLAGS) \
+ $(Xrandr_CFLAGS) \
+ $(Xtst_CFLAGS) \
+ $(NULL)
+
+AM_CXXFLAGS = \
+ $(BASE_CXXFLAGS) \
+ $(NULL)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/../nx-X11/exports/include \
+ $(NULL)
+
+libXcompshad_la_LDFLAGS = -version-number @LT_COMPSHAD_VERSION@ -no-undefined
+
+libXcompshadincludedir = $(includedir)/nx
+libXcompshadinclude_HEADERS = \
+ $(top_srcdir)/include/Shadow.h \
+ $(NULL)
diff --git a/nxcompshad/src/Manager.cpp b/nxcompshad/src/Manager.cpp
new file mode 100644
index 000000000..6e3f6b1b0
--- /dev/null
+++ b/nxcompshad/src/Manager.cpp
@@ -0,0 +1,264 @@
+/**************************************************************************/
+/* */
+/* 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 <nx-X11/Xlib.h>
+#include <nx-X11/Xutil.h>
+#include <nx-X11/keysym.h>
+#include <string.h>
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+
+#include "Manager.h"
+#include "Logger.h"
+
+UpdateManager::UpdateManager(int w, int h, char *f, Input *i)
+ : width_(w), height_(h), frameBuffer_(f), input_(i)
+{
+ logTrace("UpdateManager::UpdateManager");
+
+ nUpdater = 0;
+ updaterVector = NULL;
+ updateManagerRegion_ = NULL;
+}
+
+UpdateManager::~UpdateManager()
+{
+ logTrace("UpdateManager::~UpdateManager");
+
+ for (int i = 0; i < nUpdater; i++)
+ {
+ delete updaterVector[i];
+ }
+
+ delete [] updaterVector;
+}
+
+Updater *UpdateManager::createUpdater(char *displayName, Display *display)
+{
+ Updater *updater = new Updater(displayName, display);
+
+ if (updater == NULL)
+ {
+ logError("UpdateManager::createUpdater", ESET(ENOMEM));
+
+ return NULL;
+ }
+
+ if (updater -> init(width_, height_, frameBuffer_, input_) == -1)
+ {
+ logError("UpdateManager::createUpdater", EGET());
+
+ delete updater;
+
+ return NULL;
+ }
+
+ return updater;
+}
+
+UpdaterHandle UpdateManager::addUpdater(char *displayName, Display *display)
+{
+ Updater *newUpdater = createUpdater(displayName, display);
+
+ if (newUpdater == NULL)
+ {
+ logError("UpdateManager::addUpdater", EGET());
+
+ return NULL;
+ }
+
+ Updater **newUpdaterVector = new Updater*[nUpdater + 1];
+
+ if (newUpdaterVector == NULL)
+ {
+ logError("UpdateManager::addUpdater", ESET(ENOMEM));
+
+ delete newUpdater;
+
+ return NULL;
+ }
+
+ for (int i = 0; i < nUpdater; i++)
+ {
+ newUpdaterVector[i] = updaterVector[i];
+ }
+
+ newUpdaterVector[nUpdater] = newUpdater;
+
+ delete [] updaterVector;
+
+ updaterVector = newUpdaterVector;
+
+ nUpdater++;
+
+ logTest("UpdateManager::AddUpdater", "Number of updaters [%d].", nUpdater);
+
+ return reinterpret_cast<UpdaterHandle>(newUpdater);
+}
+
+int UpdateManager::removeAllUpdaters()
+{
+ logTest("UpdateManager::removeAllUpdaters", "Number of updaters [%d].", nUpdater);
+
+ int nullUpdaters = 0;
+
+ for (int i = nUpdater; i > 0; i--)
+ {
+ if (removeUpdater(reinterpret_cast<UpdaterHandle>(updaterVector[i - 1])) == 0)
+ {
+ nullUpdaters++;
+ }
+ }
+
+ if (nUpdater == 0)
+ {
+ return 1;
+ }
+
+ if (nUpdater == nullUpdaters)
+ {
+ logTest("UpdateManager::removeAllUpdaters", "Ignored null records in Updater vector.");
+
+ return 0;
+ }
+
+ logTest("UpdateManager::removeAllUpdaters", "Failed to remove some updaters.");
+
+ return -1;
+}
+
+int UpdateManager::removeUpdater(UpdaterHandle handle)
+{
+ Updater * const updater = (Updater*) handle;
+
+ logTest("UpdateManager::removeUpdater", "Removing Updater [%p].", updater);
+
+ if (updater == NULL)
+ {
+ return 0;
+ }
+
+ for (int i = 0; i < nUpdater; i++)
+ {
+ if (updater == updaterVector[i])
+ {
+ updaterVector[i] = updaterVector[nUpdater - 1];
+
+ nUpdater--;
+
+ delete updater;
+
+ return 1;
+ }
+ }
+
+ logTest("UpdateManager::removeUpdater", "Couldn't find Updater [%p].", updater);
+
+ return -1;
+}
+
+void UpdateManager::addRegion(Region region)
+{
+ logTrace("UpdateManager::addRegion");
+
+ for (int i = 0; i < nUpdater; i++)
+ {
+ updaterVector[i] -> addRegion(region);
+ }
+
+ XDestroyRegion(region);
+}
+
+void UpdateManager::update()
+{
+ logTrace("UpdateManager::update");
+
+ for (int i = 0; i < nUpdater; i++)
+ {
+ /*updaterVector[i] -> update();*/
+ if (updaterVector[i] -> getUpdateRegion())
+ {
+ logDebug("UpdateManager::update", "pRegion [%p] rect[%ld].",
+ updaterVector[i] -> getUpdateRegion(), (updaterVector[i] -> getUpdateRegion()) -> numRects);
+
+ updateManagerRegion_ = updaterVector[i] -> getUpdateRegion();
+ //
+ // FIXME: Remove me.
+ //
+ for (int j = 0; j < updateManagerRegion_ -> numRects; j++)
+ {
+ int x = updateManagerRegion_ -> rects[j].x1;
+ int y = updateManagerRegion_ -> rects[j].y1;
+ unsigned int width = updateManagerRegion_ -> rects[j].x2 - updateManagerRegion_ -> rects[j].x1;
+ unsigned int height = updateManagerRegion_ -> rects[j].y2 - updateManagerRegion_ -> rects[j].y1;
+ logDebug("UpdateManager::update", "x[%d]y[%d]width[%u]height[%u], updateManagerRegion_[%p]",
+ x, y, width, height, updateManagerRegion_);
+ }
+ }
+ }
+}
+
+void UpdateManager::handleInput()
+{
+ logTrace("UpdateManager::handleInput");
+
+ for (int i = 0; i < nUpdater; i++)
+ {
+ try
+ {
+ updaterVector[i] -> handleInput();
+ }
+ catch (UpdaterClosing u)
+ {
+ logTest("UpdateManager::handleInput", "Catched exception UpdaterClosing().");
+
+ removeUpdater((UpdaterHandle)updaterVector[i]);
+
+ //
+ // Now the i-element of the updaterVector
+ // is changed. We don't want to skip it.
+ //
+
+ i--;
+ }
+ }
+}
+
+void UpdateManager::newRegion()
+{
+ logTrace("UpdateManager::newRegion");
+
+ for (int i = 0; i < nUpdater; i++)
+ {
+ updaterVector[i] -> newRegion();
+ }
+}
diff --git a/nxcompshad/src/Manager.h b/nxcompshad/src/Manager.h
new file mode 100644
index 000000000..92a82cd32
--- /dev/null
+++ b/nxcompshad/src/Manager.h
@@ -0,0 +1,123 @@
+/**************************************************************************/
+/* */
+/* 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. */
+/* */
+/**************************************************************************/
+
+#ifndef UpdateManager_H
+#define UpdateManager_H
+
+#include <nx-X11/Xlib.h>
+
+#include "Updater.h"
+#include "Regions.h"
+#include "Input.h"
+
+typedef char* UpdaterHandle;
+
+class UpdateManager
+{
+ public:
+
+ UpdateManager(int, int, char *, Input *);
+
+ ~UpdateManager();
+
+ void handleInput();
+
+ void addRegion(Region);
+
+ void update();
+
+ UpdaterHandle addUpdater(char *displayName, Display *display);
+
+ int removeUpdater(UpdaterHandle);
+
+ int removeAllUpdaters();
+
+ int numberOfUpdaters();
+
+ int getWidth();
+
+ int getHeight();
+
+ char *getBuffer();
+
+ Region getUpdateManagerRegion();
+
+ void destroyUpdateManagerRegion();
+
+ void newRegion();
+
+ private:
+
+ Updater *createUpdater(char *displayName, Display *display);
+
+ int width_;
+ int height_;
+ char *frameBuffer_;
+ Input *input_;
+
+ int nUpdater;
+
+ Updater **updaterVector;
+
+ Region updateManagerRegion_;
+
+};
+
+inline int UpdateManager::numberOfUpdaters()
+{
+ return nUpdater;
+}
+
+inline int UpdateManager::getWidth()
+{
+ return width_;
+}
+
+inline int UpdateManager::getHeight()
+{
+ return height_;
+}
+
+inline char *UpdateManager::getBuffer()
+{
+ return frameBuffer_;
+}
+
+inline Region UpdateManager::getUpdateManagerRegion()
+{
+ return updateManagerRegion_;
+}
+
+inline void UpdateManager::destroyUpdateManagerRegion()
+{
+ if (updateManagerRegion_ != NULL)
+ {
+ XDestroyRegion(updateManagerRegion_);
+
+ updateManagerRegion_ = NULL;
+ }
+}
+
+#endif /* UpdateManager_H */
diff --git a/nxcompshad/src/Misc.h b/nxcompshad/src/Misc.h
new file mode 100644
index 000000000..9386dc080
--- /dev/null
+++ b/nxcompshad/src/Misc.h
@@ -0,0 +1,50 @@
+/**************************************************************************/
+/* */
+/* 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. */
+/* */
+/**************************************************************************/
+
+#ifndef Misc_H
+#define Misc_H
+
+#include <iostream>
+
+#include <cerrno>
+#include <cstring>
+
+using namespace std;
+
+//
+// Error handling macros.
+//
+
+#define ESET(e) (errno = (e))
+#define EGET() (errno)
+#define ESTR() strerror(errno)
+
+//
+// Log file.
+//
+
+extern ostream *logofs;
+
+#endif /* Misc_H */
diff --git a/nxcompshad/src/Poller.h b/nxcompshad/src/Poller.h
new file mode 100644
index 000000000..6236f872f
--- /dev/null
+++ b/nxcompshad/src/Poller.h
@@ -0,0 +1,39 @@
+/**************************************************************************/
+/* */
+/* 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. */
+/* */
+/**************************************************************************/
+
+#ifndef Poller_H
+#define Poller_H
+
+#if defined(__CYGWIN32__) || defined(WIN32)
+
+#include "Win.h"
+
+#else
+
+#include "X11.h"
+
+#endif
+
+#endif /* Poller_H */
diff --git a/nxcompshad/src/Regions.h b/nxcompshad/src/Regions.h
new file mode 100644
index 000000000..59fdcb46c
--- /dev/null
+++ b/nxcompshad/src/Regions.h
@@ -0,0 +1,43 @@
+/**************************************************************************/
+/* */
+/* 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. */
+/* */
+/**************************************************************************/
+
+#ifndef Region_H
+#define Region_H
+
+#include <nx-X11/Xlib.h>
+#include <nx-X11/Xutil.h>
+
+typedef struct {
+ short x1, x2, y1, y2;
+} Box, BOX, BoxRec, *BoxPtr;
+
+typedef struct _XRegion {
+ long size;
+ long numRects;
+ BOX *rects;
+ BOX extents;
+};
+
+#endif /* Region_H */
diff --git a/nxcompshad/src/Shadow.cpp b/nxcompshad/src/Shadow.cpp
new file mode 100644
index 000000000..3db5039ce
--- /dev/null
+++ b/nxcompshad/src/Shadow.cpp
@@ -0,0 +1,482 @@
+/**************************************************************************/
+/* */
+/* 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 <signal.h>
+#include <string.h>
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+
+#include "Logger.h"
+#include "Shadow.h"
+#include "Poller.h"
+#include "Manager.h"
+
+typedef struct {
+ KeySym *map;
+ KeyCode minKeyCode,
+ maxKeyCode;
+ int mapWidth;
+} KeySymsRec, *KeySymsPtr;
+
+KeySymsPtr NXShadowKeymap = NULL;
+
+ShadowOptions NXShadowOptions = {1, 1, -1};
+
+static int mirrorException = 0;
+
+static UpdateManager *updateManager;
+static Poller *poller;
+static Input *input;
+
+int NXShadowRemoveAllUpdaters();
+
+inline bool NXShadowNotInitialized()
+{
+ //
+ // updateManager depends on input and poller.
+ // So this test seem redundant.
+ //
+ // return (input == NULL) || (poller == NULL) || (updateManager == NULL);
+ //
+
+ return (updateManager == NULL);
+}
+
+#ifdef NEED_SIGNAL_HANDLER
+static void NXSignalHandler(int signal)
+{
+ logTest("NXSignalHandler", "Got signal [%d]", signal);
+
+ if (signal == SIGINT)
+ {
+ mirrorException = 1;
+ }
+ else if (signal == SIGTERM)
+ {
+ mirrorException = 1;
+ }
+}
+
+static int NXInitSignal()
+{
+ logTrace("NXInitSignal");
+
+ struct sigaction sa;
+
+ sa.sa_handler = NXSignalHandler;
+ sigfillset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ int res;
+
+ while ((res = sigaction(SIGINT, &sa, NULL)) == -1 &&
+ errno == EINTR);
+
+ if (res == -1)
+ {
+ logError("NXInitSignal", EGET());
+
+ return -1;
+ }
+
+ return 1;
+}
+#endif
+
+static void NXHandleException()
+{
+ if (mirrorException)
+ {
+ mirrorException = 0;
+
+ NXShadowRemoveAllUpdaters();
+ }
+}
+
+static int NXCreateInput(char *keymap, char *shadowDisplayName)
+{
+ logTrace("NXCreateInput");
+
+ input = new Input;
+
+ if (input == NULL)
+ {
+ logError("NXCreateInput", ESET(ENOMEM));
+
+ return -1;
+ }
+
+ input -> setKeymap(keymap);
+
+ input -> setShadowDisplayName(shadowDisplayName);
+
+ return 1;
+}
+
+static int NXCreatePoller(Display *display, Display **shadowDisplay)
+{
+ logTrace("NXCreatePoller");
+
+ if (input == NULL)
+ {
+ logError("NXCreatePoller", ESET(EBADF));
+
+ return -1;
+ }
+
+ poller = new Poller(input,display);
+
+ if (poller == NULL)
+ {
+ logError("NXCreatePoller", ESET(ENOMEM));
+
+ return -1;
+ }
+
+ if (poller -> init() == -1)
+ {
+ logWarning("NXCreatePoller", "Failed to initialize poller.");
+
+ return -1;
+ }
+
+ *shadowDisplay = poller -> getShadowDisplay();
+
+ logTest("NXCreatePoller", "Poller geometry [%d, %d], ShadowDisplay[%p].", poller -> width(),
+ poller -> height(), (Display *) *shadowDisplay);
+
+ return 1;
+}
+
+static int NXCreateUpdateManager()
+{
+ logTrace("NXCreateUpdateManager");
+
+ if (input == NULL || poller == NULL)
+ {
+ logError("NXCreateUpdateManager", ESET(EBADF));
+
+ return -1;
+ }
+
+ updateManager = new UpdateManager(poller -> width(), poller -> height(),
+ poller -> getFrameBuffer(), input);
+
+ if (updateManager == NULL)
+ {
+ logError("NXCreateUpdateManager", ESET(ENOMEM));
+
+ return -1;
+ }
+
+ return 1;
+}
+
+void NXShadowResetOptions()
+{
+ NXShadowOptions.optionShmExtension = 1;
+ NXShadowOptions.optionDamageExtension = 1;
+}
+
+//
+// Exported functions.
+//
+
+int NXShadowHasUpdaters()
+{
+ logTrace("NXShadowHasUpdaters");
+
+ return (updateManager && updateManager -> numberOfUpdaters()) ? 1 : 0;
+}
+
+int NXShadowRemoveAllUpdaters()
+{
+ logTrace("NXShadowRemoveAllUpdaters");
+
+ return updateManager ? updateManager -> removeAllUpdaters() : 0;
+}
+
+int NXShadowRemoveUpdater(UpdaterHandle handle)
+{
+ logTrace("NXShadowRemoveUpdater");
+
+ return updateManager ? updateManager -> removeUpdater(handle) : 0;
+}
+
+UpdaterHandle NXShadowAddUpdater(char *displayName)
+{
+ logTrace("NXShadowAddUpdater");
+
+ return updateManager ? updateManager -> addUpdater(displayName, NULL) : NULL;
+}
+
+int NXShadowAddUpdaterDisplay(void *dpy, int *w, int *h, unsigned char *d)
+{
+ Display *display = reinterpret_cast<Display*>(dpy);
+
+ logTrace("NXShadowAddUpdaterDisplay");
+
+ if ((updateManager ? updateManager -> addUpdater(NULL, display) : NULL) == NULL)
+ {
+ logTest("NXShadowAddUpdaterDisplay", "Error");
+
+ return 0;
+ }
+
+ *w = updateManager -> getWidth();
+ *h = updateManager -> getHeight();
+ *d = poller -> depth();
+
+ return 1;
+}
+
+int NXShadowCreate(void *dpy, char *keymap, char* shadowDisplayName, void **shadowDpy)
+{
+ logTrace("NXShadowCreate");
+
+ Display *display = reinterpret_cast<Display*>(dpy);
+ Display **shadowDisplay = reinterpret_cast<Display**>(shadowDpy);
+
+/* if (NXInitSignal() != 1)
+ {
+ logError("NXShadowCreate", EGET());
+
+ return -1;
+ }*/
+
+ if (NXCreateInput(keymap, shadowDisplayName) != 1)
+ {
+ logError("NXShadowCreate", EGET());
+
+ return -1;
+ }
+
+ if (NXCreatePoller(display, shadowDisplay) != 1)
+ {
+ logWarning("NXShadowCreate", "NXCreatePoller failed.");
+
+ return -1;
+ }
+
+ if (NXCreateUpdateManager() != 1)
+ {
+ logError("NXShadowCreate", EGET());
+
+ return -1;
+ }
+
+ return 1;
+}
+
+#if !defined(__CYGWIN32__) && !defined(WIN32)
+
+void NXShadowSetDisplayUid(int uid)
+{
+ NXShadowOptions.optionShadowDisplayUid = uid;
+}
+
+void NXShadowDisableShm(void)
+{
+ logUser("NXShadowDisableShm: Disabling SHM.\n");
+
+ NXShadowOptions.optionShmExtension = 0;
+}
+
+void NXShadowDisableDamage(void)
+{
+ NXShadowOptions.optionDamageExtension = 0;
+}
+
+void NXShadowGetScreenSize(int *w, int *h)
+{
+ poller -> getScreenSize(w, h);
+}
+
+void NXShadowSetScreenSize(int *w, int *h)
+{
+ poller -> setScreenSize(w, h);
+}
+
+#endif
+
+void NXShadowDestroy()
+{
+ if (poller)
+ {
+ delete poller;
+
+ poller = NULL;
+ }
+
+ if (updateManager)
+ {
+ delete updateManager;
+
+ updateManager = NULL;
+ }
+
+ if (input)
+ {
+ delete input;
+
+ input = NULL;
+ }
+}
+
+void NXShadowHandleInput()
+{
+ logTrace("NXShadowHandleInput");
+
+ if (NXShadowNotInitialized())
+ {
+ logError("NXShadowHandleInput - NXShadow not properly initialized.", ESET(EBADF));
+
+ return;
+ }
+
+ NXHandleException();
+
+ updateManager -> handleInput();
+
+ poller -> handleInput();
+}
+
+int NXShadowHasChanged(int (*callback)(void *), void *arg, int *suspended)
+{
+ int result;
+
+ logTrace("NXShadowHasChanged");
+
+ if (NXShadowNotInitialized())
+ {
+ logError("NXShadowHasChanged - NXShadow not properly initialized.", ESET(EBADF));
+
+ return -1;
+ }
+
+ //
+ // FIXME
+ //updateManager -> destroyUpdateManagerRegion();
+ //
+
+ updateManager -> newRegion();
+
+#if !defined(__CYGWIN32__) && !defined(WIN32)
+ poller -> getEvents();
+#endif
+
+ result = poller -> isChanged(callback, arg, suspended);
+
+ if (result == 1)
+ {
+ updateManager -> addRegion(poller -> lastUpdatedRegion());
+
+ return 1;
+ }
+ else if (result == -1)
+ {
+ logTest("NXShadowHasChanged", "Scanline error.");
+ return -1;
+ }
+
+ return 0;
+}
+
+void NXShadowExportChanges(long *numRects, char **pBox)
+{
+ Region pReg;
+
+ logTrace("NXShadowExportChanges");
+
+ if (NXShadowNotInitialized())
+ {
+ logError("NXShadowExportChanges - NXShadow not properly initialized.", ESET(EBADF));
+ }
+
+ updateManager -> update();
+ pReg = updateManager -> getUpdateManagerRegion();
+ *numRects = pReg -> numRects;
+ *pBox = (char *)pReg -> rects;
+
+ logTest("NXShadowExportChanges", "numRects [%ld] pBox[%p], pReg->numRects[%ld], rects[%p], size[%lu]",
+ *numRects, *pBox, pReg -> numRects, &(pReg -> rects -> x2),
+ (unsigned long) sizeof(pReg -> rects -> x2));
+}
+
+void NXShadowEvent(Display *display, XEvent event)
+{
+ poller -> handleEvent(display, &event);
+}
+
+void NXShadowWebKeyEvent(KeySym keysym, Bool isKeyPress)
+{
+ poller -> handleWebKeyEvent(keysym, isKeyPress);
+}
+
+#ifdef __CYGWIN32__
+
+int NXShadowCaptureCursor(unsigned int wnd, void *vis)
+{
+ Window window = (Window)wnd;
+ Visual *visual = reinterpret_cast<Visual*>(vis);
+
+ logTrace("NXShadowCaptureCursor");
+
+ logTest("NXShadowCaptureCursor","Init");
+
+ return poller -> updateCursor(window, visual);
+}
+
+#endif
+
+void NXShadowUpdateBuffer(void **buffer)
+{
+ char **fBuffer = reinterpret_cast<char **>(buffer);
+
+ if (*fBuffer != NULL)
+ {
+ poller -> destroyFrameBuffer();
+
+ poller -> init();
+ }
+
+ *fBuffer = poller -> getFrameBuffer();
+
+ logTest("NXShadowUpdateBuffer","New frame buffer [0x%p]", (void *)*fBuffer);
+}
+
+void NXShadowInitKeymap(void *keysyms)
+{
+ NXShadowKeymap = (KeySymsPtr) keysyms;
+
+ logTest("NXShadowInitKeymap","KeySyms pointer [0x%p]", (void *)NXShadowKeymap);
+}
diff --git a/nxcompshad/src/Updater.cpp b/nxcompshad/src/Updater.cpp
new file mode 100644
index 000000000..4b677a78c
--- /dev/null
+++ b/nxcompshad/src/Updater.cpp
@@ -0,0 +1,395 @@
+/**************************************************************************/
+/* */
+/* 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 <nx-X11/Xlib.h>
+#include <nx-X11/Xutil.h>
+#include <nx-X11/keysym.h>
+#include <string.h>
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+//
+#include <stdio.h>
+//
+#include "Updater.h"
+#include "Logger.h"
+
+Updater::Updater(char *displayName, Display *display)
+{
+ logTrace("Updater::Updater");
+
+ displayName_ = displayName;
+ display_ = display;
+ closeDisplay_ = false;
+ image_ = NULL;
+ updateRegion_ = NULL;
+ buffer_ = NULL;
+}
+
+Updater::~Updater()
+{
+ logTrace("Updater::~Updater");
+
+ if (input_)
+ {
+ int removedEvents = input_ -> removeAllEvents(display_);
+
+ logTest("Updater::~Updater", "Removed events in input queue is [%d].", removedEvents);
+ }
+
+ if (display_)
+ {
+ XDestroyWindow(display_, window_);
+ XFreePixmap(display_, pixmap_);
+
+ if (closeDisplay_)
+ {
+ XCloseDisplay(display_);
+ }
+ }
+
+ if (image_)
+ {
+ image_ -> data = NULL;
+
+ XDestroyImage(image_);
+ }
+
+ if (updateRegion_)
+ {
+ XDestroyRegion(updateRegion_);
+ }
+}
+
+int Updater::init(int width, int height, char *fb, Input *input)
+{
+ logTrace("Updater::init");
+
+ if (fb == NULL || input == NULL || width <= 0 || height <= 0)
+ {
+ logError("Updater::init", ESET(EINVAL));
+
+ return -1;
+ }
+
+ width_ = width;
+ height_ = height;
+ buffer_ = fb;
+ input_ = input;
+/*
+ if (display_ == NULL)
+ {
+ display_ = XOpenDisplay(displayName_);
+
+ closeDisplay_ = true;
+
+ if (display_ == NULL)
+ {
+ logError("Updater::init", ESET(ENOMSG));
+
+ return -1;
+ }
+ }
+*/
+ depth_ = DefaultDepth(display_, DefaultScreen(display_));
+
+ if (depth_ == 8) bpl_ = width_;
+ else if (depth_ == 16) bpl_ = width_ * 2;
+ else bpl_ = width_ * 4;
+
+ logTest("Updater::init", "Server geometry [%d, %d] depth [%d] bpl [%d].", width_, height_, depth_, bpl_);
+
+/* int bitmap_pad = 8;
+
+ image_ = XCreateImage(display_, DefaultVisual(display_, DefaultScreen(display_)), depth_, ZPixmap, 0,
+ buffer_, width_, height_, bitmap_pad, 0);
+
+ if (image_ == NULL)
+ {
+ logError("Updater::init", ESET(ENOMSG));
+
+ logTest("Updater::init", "Failed to create default image.");
+
+ return -1;
+ }
+
+ pixmap_ = XCreatePixmap(display_, DefaultRootWindow(display_), width_, height_, depth_);
+
+ unsigned int mask = CWBackPixmap | CWBorderPixel | CWEventMask;
+
+ XSetWindowAttributes attributes;
+
+ attributes.background_pixmap = pixmap_;
+ attributes.border_pixel = WhitePixel(display_, DefaultScreen(display_));
+ attributes.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;
+
+ window_ = XCreateWindow(display_, DefaultRootWindow(display_),
+ 0, 0, width_, height_, 0, depth_, InputOutput,
+ DefaultVisual(display_, DefaultScreen(display_)), mask, &attributes);
+
+ if (window_ == None)
+ {
+ logError("Updater::init", ESET(ENOMSG));
+
+ return -1;
+ }
+
+ XSizeHints *size_hints;
+
+ if ((size_hints = XAllocSizeHints()) == NULL)
+ {
+ logError("Updater::init", ESET(ENOMEM));
+
+ return -1;
+ }
+
+ size_hints -> flags = PMinSize | PMaxSize;
+ size_hints -> min_width = width_;
+ size_hints -> max_width = width_;
+ size_hints -> min_height = height_;
+ size_hints -> max_height = height_;
+
+ XSetWMNormalHints(display_, window_, size_hints);
+
+ XFree(size_hints);
+
+ Atom deleteWMatom = XInternAtom(display_, "WM_DELETE_WINDOW", 1);
+
+ XSetWMProtocols(display_, window_, &deleteWMatom, 1);
+
+ XMapWindow(display_, window_);*/
+
+ updateRegion_ = XCreateRegion();
+
+ logTest("Updater::init", "updateRegion_[%p]", updateRegion_);
+ return 1;
+}
+
+void Updater::addRegion(Region region)
+{
+ //
+ // FIXME: Is this too paranoid ?
+ //
+
+ if (updateRegion_ == NULL)
+ {
+ logError("Updater::addRegion", ESET(EINVAL));
+
+ return;
+ }
+
+ XUnionRegion(region, updateRegion_, updateRegion_);
+}
+
+void Updater::update()
+{
+ logTrace("Updater::update");
+
+ if (updateRegion_ == NULL)
+ {
+ logError("Updater::update", ESET(EINVAL));
+
+ return;
+ }
+
+ logTest("Updater::update", "Number of rectangles [%ld].", updateRegion_ -> numRects);
+
+/* for (; updateRegion_ -> numRects > 0; updateRegion_ -> numRects--)
+ {
+ int n = updateRegion_ -> numRects - 1;
+
+ int x = updateRegion_ -> rects[n].x1;
+ int y = updateRegion_ -> rects[n].y1;
+ unsigned int width = updateRegion_ -> rects[n].x2 - updateRegion_ -> rects[n].x1;
+ unsigned int height = updateRegion_ -> rects[n].y2 - updateRegion_ -> rects[n].y1;
+
+ logDebug("Updater::update", "Sending rectangle: [%d, %d, %d, %d].", x, y, width, height);
+
+ //
+ // We need to update the extents.
+ //
+
+ int bitmap_pad;
+
+ if (depth_ == 32 || depth_ == 24)
+ {
+ bitmap_pad = 32;
+ }
+ else if (depth_ == 16)
+ {
+ if ((width & 1) == 0)
+ {
+ bitmap_pad = 32;
+ }
+ else
+ {
+ bitmap_pad = 16;
+ }
+ }
+ else if ((width & 3) == 0)
+ {
+ bitmap_pad = 32;
+ }
+ else if ((width & 1) == 0)
+ {
+ bitmap_pad = 16;
+ }
+ else
+ {
+ bitmap_pad = 8;
+ }*/
+
+/* image_ -> bitmap_pad = bitmap_pad;*/
+
+ /* NXShadowCorrectColor(x, y, width, height);*/
+
+/* XPutImage(display_, pixmap_, DefaultGC(display_, DefaultScreen(display_)),
+ image_, x, y, x, y, width, height);
+
+ XClearArea(display_, window_, x, y, width, height, 0);
+ }*/
+
+ //
+ // Should we reduces the box vector ?
+ //
+ // BOX *box = Xrealloc(updateRegion_ -> rects,
+ // updateRegion_ -> numRects == 0 ? sizeof(BOX) :
+ // updateRegion_ -> numRects * sizeof(BOX));
+ //
+ // if (box)
+ // {
+ // updateRegion_ -> rects = box;
+ // updateRegion_ -> size = 1;
+ // }
+ //
+
+ if (updateRegion_ -> numRects == 0)
+ {
+ updateRegion_ -> extents.x1 = 0;
+ updateRegion_ -> extents.y1 = 0;
+ updateRegion_ -> extents.x2 = 0;
+ updateRegion_ -> extents.y2 = 0;
+ }
+ else
+ {
+ //
+ // FIXME: We have to update the region extents.
+ //
+
+ logTest("Updater::update", "Region extents has not been updated.");
+ }
+}
+
+void Updater::handleInput()
+{
+ logTrace("Updater::handleInput");
+
+ XEvent *event = new XEvent;
+
+ if (event == NULL)
+ {
+ logError("Updater::handleInput", ESET(ENOMEM));
+
+ return;
+ }
+
+ while (XCheckIfEvent(display_, event, anyEventPredicate, NULL))
+ {
+ switch (event -> type)
+ {
+ /* case ClientMessage:
+ {
+ Atom wmProtocols = XInternAtom(display_, "WM_PROTOCOLS", 0);
+ Atom wmDeleteWindow = XInternAtom(display_, "WM_DELETE_WINDOW", 0);
+
+ if (event -> xclient.message_type == wmProtocols &&
+ (Atom)event -> xclient.data.l[0] == wmDeleteWindow)
+ {
+ logTest("Updater::handleInput", "Got client message of type WM_PROTOCOLS and value WM_DELETE_WINDOW,"
+ " throwing exception UpdaterClosing.");
+
+ delete event;
+
+ throw UpdaterClosing();
+ }
+ else
+ {
+ logTest("Updater::handleInput", "Unexpected client message type [%ld] format [%d] first value [%ld]",
+ event -> xclient.message_type, event -> xclient.format, event -> xclient.data.l[0]);
+ }
+
+ break;
+ }*/
+ case KeyPress:
+ case KeyRelease:
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ {
+ input_ -> pushEvent(display_, event);
+
+ event = new XEvent;
+
+ if (event == NULL)
+ {
+ logError("Updater::handleInput", ESET(ENOMEM));
+
+ return;
+ }
+
+ break;
+ }
+ default:
+ {
+ logTest("Updater::handleInput", "Handling unexpected event [%d].", event -> type);
+
+ break;
+ }
+ }
+ }
+
+ delete event;
+}
+
+void Updater::newRegion()
+{
+ if (updateRegion_ != NULL)
+ {
+ XDestroyRegion(updateRegion_);
+ }
+
+ updateRegion_ = XCreateRegion();
+
+ logTest("Updater::newRegion", "updateRegion_ [%p].", updateRegion_);
+}
+//
+// Private functions.
+//
diff --git a/nxcompshad/src/Updater.h b/nxcompshad/src/Updater.h
new file mode 100644
index 000000000..10d75c0d6
--- /dev/null
+++ b/nxcompshad/src/Updater.h
@@ -0,0 +1,103 @@
+/**************************************************************************/
+/* */
+/* 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. */
+/* */
+/**************************************************************************/
+
+#ifndef Updater_H
+#define Updater_H
+
+#include <nx-X11/Xlib.h>
+
+#include "Regions.h"
+#include "Input.h"
+
+class UpdaterClosing {};
+
+class Updater
+{
+ public:
+
+ Updater(char *displayName, Display *display);
+
+ ~Updater();
+
+ int init(int, int, char *, Input*);
+
+ void addRegion(Region r);
+
+ void update();
+
+ void handleInput();
+
+ XImage *getImage();
+
+ Region getUpdateRegion();
+
+ void newRegion();
+
+ private:
+
+ Input *input_;
+
+ static inline Bool anyEventPredicate(Display*, XEvent*, XPointer);
+
+ void handleKeyboardEvent(XEvent &event);
+
+ char *displayName_;
+
+ char *buffer_;
+
+ bool closeDisplay_;
+
+ Display *display_;
+
+ int depth_;
+
+ int width_;
+ int height_;
+
+ int bpl_;
+
+ Window window_;
+ XImage *image_;
+
+ Pixmap pixmap_;
+
+ Region updateRegion_;
+
+};
+
+Bool Updater::anyEventPredicate(Display*, XEvent*, XPointer)
+{
+ return true;
+}
+
+inline XImage* Updater::getImage()
+{
+ return image_;
+}
+inline Region Updater::getUpdateRegion()
+{
+ return updateRegion_;
+}
+#endif /* Updater_H */
diff --git a/nxcompshad/src/Win.cpp b/nxcompshad/src/Win.cpp
new file mode 100644
index 000000000..6033f2c1b
--- /dev/null
+++ b/nxcompshad/src/Win.cpp
@@ -0,0 +1,1149 @@
+/**************************************************************************/
+/* */
+/* 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
+
+#if defined(__CYGWIN32__) || defined(WIN32)
+
+#include <nx-X11/keysym.h>
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+
+#include "Poller.h"
+#include "Logger.h"
+
+Poller::Poller(Input *input, Display *display, int depth) : CorePoller(input, display)
+{
+ logTrace("Poller::Poller");
+
+ screenDC_ = NULL;
+ screenBmp_ = NULL;
+ memoryDC_ = NULL;
+ pDIBbits_ = NULL;
+ DIBBuffer_ = NULL;
+ pKey_ = NULL;
+ pMouse_ = NULL;
+ path_ = NULL;
+ keymapName_ = input -> getKeymap();
+ keymap_ = NULL;
+ toggleButtonState_ = 0;
+ serverModifierState_ = 0;
+ display_ = display;
+ depth_ = DefaultDepth(display_, DefaultScreen(display_));
+ oldCursor_ = 0;
+ xCursor_ = 0;
+}
+
+Poller::~Poller()
+{
+ logTrace("Poller::~Poller");
+
+ if (screenDC_)
+ {
+ BOOL result = ReleaseDC(NULL, screenDC_);
+
+ logTest("Poller::~Poller", "ReleaseDC returned [%d].", result);
+
+ screenDC_ = NULL;
+ }
+
+ if (memoryDC_)
+ {
+ BOOL result = DeleteDC(memoryDC_);
+
+ logTest("Poller::~Poller", "DeleteDC returned [%d].", result);
+
+ memoryDC_ = NULL;
+ }
+
+ if (screenBmp_)
+ {
+ BOOL result = DeleteObject(screenBmp_);
+
+ logTest("Poller::~Poller", "DeleteObject returned [%d].", result);
+
+ screenBmp_ = NULL;
+ }
+
+ if (DIBBuffer_)
+ {
+ logDebug("Poller::~Poller", "Delete DIBBuffer_ [%p].", DIBBuffer_);
+
+ delete [] DIBBuffer_;
+ }
+
+ if (pKey_)
+ {
+ logDebug("Poller::~Poller", " pKey_[%p].", pKey_);
+
+ delete [] pKey_;
+ }
+
+ if (pMouse_)
+ {
+ logDebug("Poller::~Poller", " pMouse_[%p].", pMouse_);
+
+ delete [] pMouse_;
+ }
+
+ if (keymap_)
+ {
+ logDebug("Poller::~Poller", " keymap_[%p].", keymap_);
+
+ delete [] keymap_;
+ }
+}
+
+int Poller::init()
+{
+ logTrace("Poller::init");
+
+ int maxLengthArrayINPUT = 6;
+
+ platformOS();
+
+ pKey_ = new INPUT [maxLengthArrayINPUT];
+
+ if (pKey_ == NULL)
+ {
+ logError("Poller::init", ESET(ENOMEM));
+
+ return -1;
+ }
+
+ for (int i = 0; i < maxLengthArrayINPUT; i++)
+ {
+ pKey_[i].type = INPUT_KEYBOARD;
+ pKey_[i].ki.wVk = (WORD) 0;
+ pKey_[i].ki.time = (DWORD) 0;
+ pKey_[i].ki.dwExtraInfo = (DWORD) 0;
+ }
+
+ pMouse_ = new INPUT;
+
+ if (pMouse_ == NULL)
+ {
+ logError("Poller::init", ESET(ENOMEM));
+
+ return -1;
+ }
+
+ pMouse_ -> type = INPUT_MOUSE;
+
+ pMouse_ -> mi.dx = 0;
+ pMouse_ -> mi.dy = 0;
+ pMouse_ -> mi.mouseData = (DWORD) 0;
+ pMouse_ -> mi.time = 0;
+ pMouse_ -> mi.dwExtraInfo = (ULONG_PTR) NULL;
+
+ screenDC_ = GetDC(NULL);
+
+ if (screenDC_ == NULL)
+ {
+ logError("Poller::init", ESET(ENOMSG));
+
+ return -1;
+ }
+
+ switch(depth_)
+ {
+ case 8:
+ {
+ depth_ = 16;
+ break;
+ }
+ case 16:
+ {
+ depth_ = 16;
+ break;
+ }
+ case 24:
+ {
+ depth_ = 32;
+ break;
+ }
+ default:
+ {
+ logError("Poller::init", ESET(EINVAL));
+
+ return -1;
+ }
+ }
+
+ width_ = GetDeviceCaps(screenDC_, HORZRES);
+ height_ = GetDeviceCaps(screenDC_, VERTRES);
+
+ bpl_ = width_ * (depth_ >> 3);
+ bpp_ = (depth_ >> 3);
+
+ logTest("Poller::init", "Screen geometry is [%d, %d] depth is [%d] bpl [%d] bpp [%d].",
+ width_, height_, depth_, bpl_, bpp_);
+
+ logTest("Poller::init", "Got device context at [%p] screen size is (%d,%d).",
+ screenDC_, width_, height_);
+
+ memoryDC_ = CreateCompatibleDC(screenDC_);
+
+ if (memoryDC_ == NULL)
+ {
+ logError("Poller::init", ESET(ENOMSG));
+
+ return -1;
+ }
+
+ //
+ // Delete the old bitmap for the memory device.
+ //
+
+ HBITMAP bitmap = (HBITMAP) GetCurrentObject(memoryDC_, OBJ_BITMAP);
+
+ if (bitmap && DeleteObject(bitmap) == 0)
+ {
+ logError("Poller::init", ESET(ENOMSG));
+ }
+
+ //
+ // Bitmap header describing the bitmap we want to get from GetDIBits.
+ //
+
+ bmi_.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi_.bmiHeader.biWidth = width_;
+ bmi_.bmiHeader.biHeight = -height_;
+ bmi_.bmiHeader.biPlanes = 1;
+ bmi_.bmiHeader.biBitCount = depth_;
+ bmi_.bmiHeader.biCompression = BI_RGB;
+ bmi_.bmiHeader.biSizeImage = 0;
+ bmi_.bmiHeader.biXPelsPerMeter = 0;
+ bmi_.bmiHeader.biYPelsPerMeter = 0;
+ bmi_.bmiHeader.biClrUsed = 0;
+ bmi_.bmiHeader.biClrImportant = 0;
+
+ screenBmp_ = CreateDIBSection(memoryDC_, &bmi_, DIB_RGB_COLORS, &pDIBbits_, NULL, 0);
+ ReleaseDC(NULL,memoryDC_);
+
+ if (screenBmp_ == NULL)
+ {
+ logTest ("Poller::init", "This video device is not supporting DIB section");
+
+ pDIBbits_ = NULL;
+
+ screenBmp_ = CreateCompatibleBitmap(screenDC_, width_, height_);
+
+ if (screenBmp_ == NULL)
+ {
+ logError("Poller::init", ESET(ENOMSG));
+
+ return -1;
+ }
+
+ if (SelectObject(memoryDC_, screenBmp_) == NULL)
+ {
+ logError("Poller::init", ESET(ENOMSG));
+
+ return -1;
+ }
+ }
+ else
+ {
+ logTest ("Poller::init", "Enabled the DIB section");
+
+ if (SelectObject(memoryDC_, screenBmp_) == NULL)
+ {
+ logError("Poller::init", ESET(ENOMSG));
+
+ return -1;
+ }
+ }
+
+ //
+ // Check if the screen device raster capabilities
+ // support the bitmap transfer.
+ //
+
+ if ((GetDeviceCaps(screenDC_, RASTERCAPS) & RC_BITBLT) == 0)
+ {
+ logTest("Poller::init", "This video device is not supporting the bitmap transfer.");
+
+ logError("Poller::init", ESET(ENOMSG));
+
+ return -1;
+ }
+
+ //
+ // Check if the memory device raster capabilities
+ // support the GetDIBits and SetDIBits functions.
+ //
+
+ if ((GetDeviceCaps(memoryDC_, RASTERCAPS) & RC_DI_BITMAP) == 0)
+ {
+ logTest("Poller::init", "This memory device is not supporting the GetDIBits and SetDIBits "
+ "function.");
+
+ logError("Poller::init", ESET(ENOMSG));
+
+ return -1;
+ }
+
+ if (GetDeviceCaps(screenDC_, PLANES) != 1)
+ {
+ logTest("Poller::init", "This video device has more than 1 color plane.");
+
+ logError("Poller::init", ESET(ENOMSG));
+
+ return -1;
+ }
+
+ return CorePoller::init();
+}
+
+//
+// FIXME: Remove me.
+//
+
+void ErrorExit(LPTSTR lpszFunction)
+{
+ LPVOID lpMsgBuf;
+ DWORD dw = GetLastError();
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ logTest(lpszFunction, " Failed with error [%ld]: %s", dw, (char*)lpMsgBuf);
+
+ LocalFree(lpMsgBuf);
+ ExitProcess(dw);
+}
+
+//
+// FIXME: End.
+//
+
+char *Poller::getRect(XRectangle r)
+{
+ logTrace("Poller::getRect");
+
+ logDebug("Poller::getRect", "Going to retrive rectangle [%d, %d, %d, %d].",
+ r.x, r.y, r.width, r.height);
+
+ //
+ // The CAPTUREBLT operation could be a very
+ // cpu-consuming task. We should make some
+ // test to see how much it is expensive.
+ // Anyway we get tooltip windows and any
+ // other special effect not included with
+ // only the SRCCOPY operation.
+ //
+
+ if (BitBlt(memoryDC_, r.x, r.y, r.width, r.height,
+ screenDC_, r.x, r.y, SRCCOPY | CAPTUREBLT) == 0)
+ {
+ logError("Poller::getRect", ESET(ENOMSG));
+
+ logTest("Poller::getRect", "Failed to perform a bit-block transfer.");
+ logTest("Poller::getRect", "bit-block error=%lu", GetLastError());
+
+ return NULL;
+ }
+
+ // bmi_.bmiHeader.biWidth = r.width;
+ // bmi_.bmiHeader.biHeight = -r.height;
+
+ if (pDIBbits_ == NULL)
+ {
+ static long nPixel = 0;
+
+ if (nPixel < r.width * r.height)
+ {
+
+ if (DIBBuffer_)
+ {
+ delete [] DIBBuffer_;
+ }
+
+ nPixel = r.width * r.height;
+
+ DIBBuffer_ = new char [nPixel * bpp_];
+
+ if (DIBBuffer_ == NULL)
+ {
+ logError("Poller::getRect", ESET(ENOMEM));
+
+ nPixel = 0;
+
+ return NULL;
+ }
+ }
+
+ if (GetDIBits(memoryDC_, screenBmp_, height_ - r.height - r.y, r.height,
+ DIBBuffer_, &bmi_, DIB_RGB_COLORS) == 0)
+ {
+ logError("Poller::getRect", ESET(ENOMSG));
+
+ logTest("Poller::getRect", "Failed to retrieve the screen bitmap.");
+
+ return NULL;
+ }
+
+ return DIBBuffer_;
+ }
+ else
+ {
+ return (char *) pDIBbits_ + r.y * bpl_ + r.x * bpp_;
+ }
+}
+
+void Poller::handleKeyboardEvent(Display *display, XEvent *event)
+{
+ KeySym keysym;
+ char *keyname = new char [31];
+ keyTranslation tr = {0, 0};
+ unsigned char scancode = 0;
+ int lengthArrayINPUT = 0;
+
+ if (XLookupString((XKeyEvent *) event, keyname, 30, &keysym, NULL) > 0)
+ {
+ logTest("Poller::handleKeyboardEvent", "keyname %s, keysym [%x]", keyname, (unsigned int)keysym);
+ }
+
+ if (specialKeys(keysym, event -> xkey.state, event -> type) == 1)
+ {
+ delete[] keyname;
+ return;
+ }
+
+ tr = xkeymapTranslateKey(keysym, event -> xkey.keycode, event -> xkey.state);
+ scancode = tr.scancode;
+
+ logTest("Poller::handleKeyboardEvent", "keyname [%s] scancode [0x%x], keycode[0x%x], keysym [%x]", keyname,
+ tr.scancode, event ->xkey.keycode, (unsigned int)keysym);
+
+ if (scancode == 0)
+ {
+ delete[] keyname;
+ return;
+ }
+
+ if (event -> type == KeyPress)
+ {
+ int test1 = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX);
+ int test2 = MapVirtualKey(0x24, MAPVK_VSC_TO_VK_EX);
+
+ if (test1 == test2)
+ {
+ simulateCtrlAltDel();
+ }
+
+ if (isModifier(scancode) == 0)
+ {
+ savedServerModifierState_ = serverModifierState_;
+ }
+
+ ensureServerModifiers(tr, &lengthArrayINPUT);
+ if (sendInput(scancode, 1, &lengthArrayINPUT) == 0)
+ {
+ logTest("Poller::handleKeyboardEvent", "lengthArrayINPUT [%d].", lengthArrayINPUT);
+ }
+ restoreServerModifiers(scancode);
+ }
+ else if (event -> type == KeyRelease)
+ {
+ if (sendInput(scancode, 0, &lengthArrayINPUT) == 0)
+ {
+ logTest("Poller::handleKeyboardEvent", "lengthArrayINPUT [%d].", lengthArrayINPUT);
+ }
+ }
+
+ updateModifierState(scancode, (event -> type == KeyPress));
+
+ delete[] keyname;
+}
+
+void Poller::handleWebKeyboardEvent(KeySym keysym, Bool isKeyPress)
+{
+/*
+FIXME
+*/
+}
+
+void Poller::handleMouseEvent(Display *display, XEvent *event)
+{
+ DWORD flg = 0;
+ DWORD whl = 0;
+
+ if (event -> type == ButtonPress)
+ {
+ logTest("Poller::handleMouseEvent", "ButtonPress.\n");
+ switch (event -> xbutton.button)
+ {
+ case Button1:
+ {
+ flg = MOUSEEVENTF_LEFTDOWN;
+ break;
+ }
+ case Button2:
+ {
+ flg = MOUSEEVENTF_MIDDLEDOWN;
+ break;
+ }
+ case Button3:
+ {
+ flg = MOUSEEVENTF_RIGHTDOWN;
+ break;
+ }
+ case Button4:
+ {
+ flg = MOUSEEVENTF_WHEEL;
+ whl = WHEEL_DELTA;
+ pMouse_ -> mi.mouseData = whl;
+ break;
+ }
+ case Button5:
+ {
+ flg = MOUSEEVENTF_WHEEL;
+ whl = (DWORD) (-WHEEL_DELTA);
+ pMouse_ -> mi.mouseData = whl;
+ break;
+ }
+ }
+ }
+ else if (event -> type == ButtonRelease)
+ {
+ switch (event -> xbutton.button)
+ {
+ case Button1:
+ {
+ flg = MOUSEEVENTF_LEFTUP;
+ break;
+ }
+ case Button2:
+ {
+ flg = MOUSEEVENTF_MIDDLEUP;
+ break;
+ }
+ case Button3:
+ {
+ flg = MOUSEEVENTF_RIGHTUP;
+ break;
+ }
+ case Button4:
+ {
+ flg = MOUSEEVENTF_WHEEL;
+ whl = 0;
+ pMouse_ -> mi.mouseData = whl;
+ break;
+ }
+ case Button5:
+ {
+ flg = MOUSEEVENTF_WHEEL;
+ whl = 0;
+ pMouse_ -> mi.mouseData = whl;
+ break;
+ }
+ }
+ }
+ else if (event -> type == MotionNotify)
+ {
+ logTest("Poller::handleMouseEvent", "SetCursor - MotionNotify");
+
+ SetCursorPos(event -> xmotion.x, event -> xmotion.y);
+ }
+
+ if (flg > 0)
+ {
+ // logTest("Poller::handleMouseEvent", "SetCursor - flg > 0");
+ //
+ // FIXME: move the cursor to the pace the event occurred
+ //
+
+ SetCursorPos(event -> xbutton.x, event -> xbutton.y);
+
+ //
+ // FIXME: Remove me: send the click/release event
+ // mouse_event(flg, 0, 0, whl, (ULONG_PTR)NULL);
+ //
+
+ pMouse_ -> mi.dwFlags = flg;
+
+ if (SendInput(1, pMouse_, sizeof(INPUT)) == 0)
+ {
+ logTest("Poller::handleMouseEvent", "Failed SendInput");
+ }
+ }
+}
+
+int Poller::updateCursor(Window wnd, Visual* vis)
+{
+ BYTE *mBits, *andBits, *xorBits;
+
+ logTrace("Poller::Cursor");
+
+ //
+ // Retrieve mouse cursor handle.
+ //
+
+ CURSORINFO cursorInfo;
+ cursorInfo.cbSize = sizeof(CURSORINFO);
+
+ if (GetCursorInfo(&cursorInfo) == 0)
+ {
+ logTest("Poller::Cursor", "GetCursorInfo() failed [%u].\n", (unsigned int)GetLastError());
+ LocalFree(&cursorInfo);
+ return -1;
+ }
+
+ HCURSOR hCursor = cursorInfo.hCursor;
+
+ if (hCursor == 0)
+ {
+ logTest("Poller::Cursor","Cursor Handle is NULL. Error[%u].\n", (unsigned int)GetLastError());
+ return 1;
+ }
+
+ if (hCursor == oldCursor_)
+ {
+ LocalFree(&cursorInfo);
+ return 1;
+ }
+ else
+ {
+ oldCursor_ = hCursor;
+ }
+
+ //
+ // Get cursor info.
+ //
+
+ // logTest("Poller::Cursor","hCursor [%xH] GetCursor [%xH].\n", hCursor, GetCursor());
+
+ ICONINFO iconInfo;
+ if (GetIconInfo(hCursor, &iconInfo) == 0)
+ {
+ logTest("Poller::Cursor","GetIconInfo() failed. Error[%d].", (unsigned int)GetLastError());
+ LocalFree(&iconInfo);
+ // return -1;
+ }
+
+ BOOL isColorCursor = FALSE;
+ if (iconInfo.hbmColor != NULL)
+ {
+ isColorCursor = TRUE;
+ }
+
+ if (iconInfo.hbmMask == NULL)
+ {
+ logTest("Poller::Cursor","Cursor bitmap handle is NULL.\n");
+ return -1;
+ }
+
+ //
+ // Check bitmap info for the cursor
+ //
+
+ BITMAP bmMask;
+ if (!GetObject(iconInfo.hbmMask, sizeof(BITMAP), (LPVOID)&bmMask))
+ {
+ logTest("Poller::Cursor","GetObject() for bitmap failed.\n");
+ DeleteObject(iconInfo.hbmMask);
+ LocalFree(&bmMask);
+ return -1;
+ }
+
+ if (bmMask.bmPlanes != 1 || bmMask.bmBitsPixel != 1)
+ {
+ logTest("Poller::Cursor","Incorrect data in cursor bitmap.\n");
+ LocalFree(&bmMask);
+ DeleteObject(iconInfo.hbmMask);
+ return -1;
+ }
+
+ // Get monochrome bitmap data for cursor
+ // NOTE: they say we should use GetDIBits() instead of GetBitmapBits().
+ mBits = new BYTE[bmMask.bmWidthBytes * bmMask.bmHeight];
+
+ if (mBits == NULL)//Data bitmap
+ {
+ DeleteObject(iconInfo.hbmMask);
+ DestroyCursor(cursorInfo.hCursor);
+ LocalFree(&iconInfo);
+ LocalFree(&bmMask);
+ delete[] mBits;
+ return -1;
+ }
+
+ BOOL success = GetBitmapBits(iconInfo.hbmMask, bmMask.bmWidthBytes * bmMask.bmHeight, mBits);
+
+ if (!success)
+ {
+ logTest("Poller::Cursor","GetBitmapBits() failed.\n");
+ delete[] mBits;
+ return -1;
+ }
+
+ andBits = mBits;
+
+ long width = bmMask.bmWidth;
+ long height = (isColorCursor) ? bmMask.bmHeight : bmMask.bmHeight/2;
+
+ //
+ // The bitmask is formatted so that the upper half is
+ // the icon AND bitmask and the lower half is the icon XOR bitmask.
+ //
+
+ if (!isColorCursor)
+ {
+ xorBits = andBits + bmMask.bmWidthBytes * height;
+
+/* logTest("Poller::Cursor","no color widthB[%ld] width[%ld] height[%ld] totByte[%ld] mbits[%ld].\n",
+ bmMask.bmWidthBytes,width,height,success,bmMask.bmHeight * bmMask.bmWidthBytes);*/
+
+ if (xCursor_ > 0)
+ {
+ XFreeCursor(display_, xCursor_);
+ }
+
+ xCursor_ = createCursor(wnd, vis, (unsigned int)iconInfo.xHotspot, (unsigned int)iconInfo.yHotspot,
+ width, height, (unsigned char *)xorBits, (unsigned char *)andBits);
+
+ XDefineCursor(display_, wnd, xCursor_);
+ }
+
+ delete []mBits;
+ DeleteObject(iconInfo.hbmMask);
+ LocalFree(&bmMask);
+ DestroyCursor(cursorInfo.hCursor);
+ LocalFree(&iconInfo);
+
+ return success;
+}
+
+unsigned char Poller::specialKeys(unsigned int keysym, unsigned int state, int pressed)
+{
+ return 0;
+}
+
+void Poller::ensureServerModifiers(keyTranslation tr, int *lengthArrayINPUT)
+{
+ return;
+}
+
+void Poller::restoreServerModifiers(UINT scancode)
+{
+ keyTranslation dummy;
+ int lengthArrayINPUT = 0;
+
+ if (isModifier(scancode) == 1)
+ {
+ return;
+ }
+
+ dummy.scancode = 0;
+ dummy.modifiers = savedServerModifierState_;
+ ensureServerModifiers(dummy, &lengthArrayINPUT);
+ if (sendInput(0, 0, &lengthArrayINPUT) == 0)
+ {
+ logTest("Poller::restoreServerModifiers", "lengthArrayINPUT [%d]", lengthArrayINPUT);
+ }
+}
+
+int Poller::updateShadowFrameBuffer(void)
+{
+ return 1;
+}
+
+void Poller::addToKeymap(char *keyname, unsigned char scancode, unsigned short modifiers, char *mapname)
+{
+ return;
+}
+
+FILE *Poller::xkeymapOpen(char *filename)
+{
+ return NULL;
+}
+
+int Poller::xkeymapRead(char *mapname)
+{
+ return 1;
+}
+
+void Poller::xkeymapInit(char *keyMapName)
+{
+ return;
+}
+
+keyTranslation Poller::xkeymapTranslateKey(unsigned int keysym, unsigned int keycode,
+ unsigned int state)
+{
+ keyTranslation tr = { 0, 0 };
+
+ return tr;
+}
+
+unsigned char Poller::getKeyState(unsigned int state, unsigned int keysym)
+{
+ return 0;
+}
+
+char *Poller::getKsname(unsigned int keysym)
+{
+ char *ksname = NULL;
+
+ return ksname;
+}
+
+//
+// Routine used to fool Winlogon into thinking CtrlAltDel was pressed
+//
+char Poller::simulateCtrlAltDel(void)
+{
+ HDESK oldDesktop = GetThreadDesktop(GetCurrentThreadId());
+
+ //
+ // Switch into the Winlogon desktop.
+ //
+ if (selectDesktopByName("Winlogon") == 0)
+ {
+ logTest("SimulateCtrlAltDelThreadFn","Failed to select logon desktop.");
+ return 0;
+ }
+
+ logTest("SimulateCtrlAltDelThreadFn","Generating ctrl-alt-del.");
+
+ //
+ // Winlogon uses hotkeys to trap Ctrl-Alt-Del.
+ //
+ PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE));
+
+ //
+ // Switch back to our original desktop.
+ //
+ if (oldDesktop != NULL)
+ {
+ selectDesktop(oldDesktop);
+ }
+
+ return 1;
+}
+
+// Switches the current thread into a different desktop by desktop handle
+// This call takes care of all the evil memory management involved
+char Poller::selectDesktop(HDESK newDesktop)
+{
+ //
+ // Only on NT.
+ //
+ if (isWinNT())
+ {
+ HDESK oldDesktop = GetThreadDesktop(GetCurrentThreadId());
+
+ DWORD dummy;
+ char newName[256];
+
+ if (GetUserObjectInformation(newDesktop, UOI_NAME, &newName, 256, &dummy) == 0)
+ {
+ logDebug("Poller::selectDesktop","GetUserObjectInformation() failed. Error[%lu].", GetLastError());
+ return 0;
+ }
+
+ logTest("Poller::selectDesktop","New Desktop to [%s] (%x) from (%x).",
+ newName, (unsigned int)newDesktop, (unsigned int)oldDesktop);
+
+ //
+ // Switch the desktop.
+ //
+ if(SetThreadDesktop(newDesktop) == 0)
+ {
+ logDebug("Poller::SelectDesktop","Unable to SetThreadDesktop(), Error=%lu.", GetLastError());
+ return 0;
+ }
+
+ //
+ // Switched successfully - destroy the old desktop.
+ //
+ if (CloseDesktop(oldDesktop) == 0)
+ {
+ logDebug("Poller::selectHdesk","Failed to close old desktop (%x), Error=%lu.",
+ (unsigned int)oldDesktop, GetLastError());
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+//
+// Switches the current thread into a different desktop, by name
+// Calling with a valid desktop name will place the thread in that desktop.
+// Calling with a NULL name will place the thread in the current input desktop.
+//
+
+char Poller::selectDesktopByName(char *name)
+{
+ //
+ // Only on NT.
+ //
+ if (isWinNT())
+ {
+ HDESK desktop;
+
+ if (name != NULL)
+ {
+ //
+ // Attempt to open the named desktop.
+ //
+ desktop = OpenDesktop(name, 0, FALSE,
+ DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
+ DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
+ DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
+ DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
+ }
+ else
+ {
+ //
+ // Open the input desktop.
+ //
+ desktop = OpenInputDesktop(0, FALSE,
+ DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
+ DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
+ DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
+ DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
+ }
+
+ if (desktop == NULL)
+ {
+ logDebug("Poller::selectDesktopByName","Unable to open desktop, Error=%lu.", GetLastError());
+ return 0;
+ }
+
+ //
+ // Switch to the new desktop
+ //
+ if (selectDesktop(desktop) == 0)
+ {
+ //
+ // Failed to enter the new desktop, so free it!
+ //
+ logDebug("Poller::selectDesktopByName","Failed to select desktop.");
+
+ if (CloseDesktop(desktop) == 0)
+ {
+ logDebug("Poller::selectDesktopByName","Failed to close desktop, Error=%lu.", GetLastError());
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+
+ return (name == NULL);
+}
+
+void Poller::platformOS()
+{
+ OSVERSIONINFO osversioninfo;
+ osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
+
+ //
+ // Get the current OS version.
+ //
+ if (GetVersionEx(&osversioninfo) == 0)
+ {
+ platformID_ = 0;
+ }
+ platformID_ = osversioninfo.dwPlatformId;
+
+//
+// versionMajor = osversioninfo.dwMajorVersion;
+// versionMinor = osversioninfo.dwMinorVersion;
+//
+}
+
+char Poller::checkDesktop()
+{
+ //
+ // Only on NT.
+ //
+ if (isWinNT())
+ {
+ //
+ // Get the input and thread desktops.
+ //
+ HDESK desktop = GetThreadDesktop(GetCurrentThreadId());
+ HDESK inputDesktop = OpenInputDesktop(0, FALSE,
+ DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
+ DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
+ DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
+ DESKTOP_SWITCHDESKTOP | GENERIC_WRITE);
+
+ if (inputDesktop == NULL)
+ {
+ return 0;
+ }
+
+ DWORD dummy;
+ char desktopName[256];
+ char inputName[256];
+
+ if (GetUserObjectInformation(desktop, UOI_NAME, &desktopName, 256, &dummy) == 0)
+ {
+ if (CloseDesktop(inputDesktop) == 0)
+ {
+ logDebug("Poller::checkDesktop", "Failed to close desktop, Error[%d].", (unsigned int)GetLastError());
+ return 0;
+ }
+ }
+
+ if (GetUserObjectInformation(inputDesktop, UOI_NAME, &inputName, 256, &dummy) == 0)
+ {
+ if (CloseDesktop(inputDesktop) == 0)
+ {
+ logDebug("Poller::checkDesktop", "Failed to close input desktop, Error[%d].", (unsigned int)GetLastError());
+ return 0;
+ }
+ }
+
+ if (strcmp(desktopName, inputName) != 0)
+ {
+ //
+ // Switch to new desktop.
+ //
+ selectDesktop(inputDesktop);
+ }
+
+ if (CloseDesktop(desktop) == 0)
+ {
+ logDebug("Poller::checkDesktop", "Failed to close input desktop, Error[%d].", (unsigned int)GetLastError());
+ return 0;
+ }
+
+ if (CloseDesktop(inputDesktop) == 0)
+ {
+ logDebug("Poller::checkDesktop", "Failed to close input desktop, Error[%d].", (unsigned int)GetLastError());
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+unsigned char Poller::isModifier(UINT scancode)
+{
+ return 0;
+}
+
+void Poller::updateModifierState(UINT scancode, unsigned char pressed)
+{
+ return;
+}
+
+Cursor Poller::createCursor(Window wnd, Visual *vis,unsigned int x, unsigned int y,
+ int width, int height, unsigned char *xormask, unsigned char *andmask)
+{
+ Pixmap maskglyph, cursorglyph;
+ XColor bg, fg;
+ Cursor xcursor;
+ unsigned char *cursor;
+ unsigned char *mask, *pmask, *pcursor, tmp;
+ int scanline, offset;
+
+ scanline = (width + 7) / 8;
+ offset = scanline * height;
+
+ pmask = andmask;
+ pcursor = xormask;
+ for (int i = 0; i < offset; i++)
+ {
+ //
+ // The pixel is black if both the bit of andmask and xormask is one.
+ //
+
+ tmp = *pcursor & *pmask;
+ *pcursor ^= tmp;
+ *pmask ^= tmp;
+
+ *pmask = ~(*pmask);
+
+ pmask++;
+ pcursor++;
+ }
+
+ cursor = new unsigned char[offset];
+ memcpy(cursor, xormask, offset);
+
+ mask = new unsigned char[offset];
+ memcpy(mask, andmask, offset);
+
+ fg.red = fg.blue = fg.green = 0xffff;
+ bg.red = bg.blue = bg.green = 0x0000;
+ fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
+
+ cursorglyph = createGlyph(wnd, vis, width, height, cursor);
+ maskglyph = createGlyph(wnd, vis, width, height, mask);
+
+ xcursor = XCreatePixmapCursor(display_, cursorglyph, maskglyph, &fg, &bg, x, y);
+
+ XFreePixmap(display_, maskglyph);
+ XFreePixmap(display_, cursorglyph);
+ delete[]mask;
+ delete[]cursor;
+
+ return xcursor;
+}
+
+Pixmap Poller::createGlyph(Window wnd, Visual *visual, int width, int height, unsigned char *data)
+{
+ XImage *image;
+ Pixmap bitmap;
+ int scanline;
+ GC glyphGC;
+
+ scanline = (width + 7) / 8;
+
+ bitmap = XCreatePixmap(display_, wnd, width, height, 1);
+ glyphGC = XCreateGC(display_, bitmap, 0, NULL);
+
+ image = XCreateImage(display_, visual, 1, ZPixmap, 0, (char *)data, width, height, 8, scanline);
+ image->byte_order = 1; // MSBFirst -- LSBFirst = 0
+ image->bitmap_bit_order = 1;
+ XInitImage(image);
+
+/* logTest("Poller::createGlyph","XPutImage on pixmap %d,%d,%d,%d.\n",
+ 0, 0, width, height);*/
+ XPutImage(display_, bitmap, glyphGC, image, 0, 0, 0, 0, width, height);
+ XFree(image);
+
+ return bitmap;
+}
+#endif /* defined(__CYGWIN32__) || defined(WIN32) */
diff --git a/nxcompshad/src/Win.h b/nxcompshad/src/Win.h
new file mode 100644
index 000000000..615f9a5f5
--- /dev/null
+++ b/nxcompshad/src/Win.h
@@ -0,0 +1,232 @@
+/**************************************************************************/
+/* */
+/* 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 __CYGWIN32__
+
+#ifndef Win32Poller_H
+#define Win32Poller_H
+
+//#include <nx-X11/X.h>
+
+#include <Windows.h>
+#include <wingdi.h>
+#include <winable.h>
+#include <winuser.h>
+
+#define CAPTUREBLT 0x40000000
+
+#define KEYEVENTF_SCANCODE 0x00000008
+#define MAPVK_VSC_TO_VK_EX 3
+//
+// The CAPTUREBLT is a raster operation used
+// in bit blit transfer.
+//
+// Using this operation includes any windows
+// that are layered on top of your window in
+// the resulting image. By default, the image
+// only contains your window.
+//
+
+#include "Core.h"
+
+typedef struct _keyTranslation
+{
+ unsigned char scancode;
+ unsigned short modifiers;
+
+}keyTranslation;
+
+class Poller : public CorePoller
+{
+ public:
+
+ Display *display_;
+ keyTranslation *keymap_;
+ unsigned char keymapLoaded_;
+ int minKeycode_;
+
+ Poller(Input *, Display *display, int = 16);
+
+ ~Poller();
+
+ int init();
+
+ int updateCursor(Window, Visual*);
+
+ private:
+
+
+ int Poller::updateShadowFrameBuffer(void);
+ void handleKeyboardEvent(Display *, XEvent *);
+ void handleWebKeyboardEvent(KeySym keysym, Bool isKeyPress);
+ void addToKeymap(char *keyname, unsigned char scancode, unsigned short modifiers, char *mapname);
+ int xkeymapRead(char *mapname);
+ FILE *xkeymapOpen(char *filename);
+ void xkeymapInit(char *keyMapName);
+ keyTranslation xkeymapTranslateKey(unsigned int keysym, unsigned int keycode, unsigned int state);
+ unsigned char getKeyState(unsigned int state, unsigned int keysym);
+ char *getKsname(unsigned int keysym);
+ unsigned char specialKeys(unsigned int keysym, unsigned int state, int pressed);
+
+ unsigned char toggleSwitch(unsigned char ToggleStateClient, unsigned char ToggleStateServer, UINT scancode,
+ int *lengthArrayINPUT);
+
+ void updateModifierState(UINT, unsigned char);
+
+ unsigned char toggleServerState(UINT scancode);
+ unsigned char keyState(UINT scancode, UINT mapType);
+ unsigned char keyStateAsync(UINT scancode);
+
+ void handleMouseEvent(Display *, XEvent *);
+
+ Cursor createCursor(Window wnd, Visual *vis, unsigned int x, unsigned int y, int width,
+ int height, unsigned char *xormask, unsigned char *andmask);
+
+ Pixmap createGlyph(Window wnd, Visual *visual, int width, int height, unsigned char *data);
+
+ char isWinNT();
+ char selectDesktop(HDESK new_desktop);
+ char selectDesktopByName(char *name);
+ void platformOS();
+ char simulateCtrlAltDel(void);
+ DWORD platformID_;
+
+ INPUT *pKey_, *pMouse_;
+
+ char *keymapName_;
+ char *path_;
+
+ unsigned char toggleButtonState_;
+ unsigned short serverModifierState_;
+ unsigned short savedServerModifierState_;
+
+ void ensureServerModifiers(keyTranslation tr, int *lenghtArrayINPUT);
+ void restoreServerModifiers(UINT scancode);
+ unsigned char isModifier(UINT scancode);
+
+ char sendInput(unsigned char scancode, unsigned char pressed, int *lengthArrayINPUT);
+
+ char *getRect(XRectangle);
+ char checkDesktop();
+
+ char *DIBBuffer_;
+
+ HCURSOR oldCursor_;
+
+ VOID *pDIBbits_;
+ HDC screenDC_;
+ HDC memoryDC_;
+ BITMAPINFO bmi_;
+ HBITMAP screenBmp_;
+
+ Cursor xCursor_;
+
+};
+
+#undef TEST
+
+inline unsigned char Poller::toggleSwitch(unsigned char ToggleStateClient, unsigned char ToggleStateServer,
+ UINT scancode, int *lengthArrayINPUT)
+{
+ return 1;
+}
+
+inline unsigned char Poller::toggleServerState(UINT scancode)
+{
+ return (GetKeyState(MapVirtualKeyEx(scancode, 3, GetKeyboardLayout((DWORD)NULL))) & 0x1);
+}
+
+inline unsigned char Poller::keyStateAsync(UINT vKeycode)
+{
+ return GetAsyncKeyState(vKeycode);
+}
+
+inline unsigned char Poller::keyState(UINT code, UINT mapType)
+{
+ if (mapType == 0)
+ {
+ //
+ // Virtual Keycode
+ //
+ return ((GetKeyState(code) & 0x80) == 0x80);
+ }
+ else
+ {
+ //
+ // scancode
+ //
+ return ((GetKeyState(MapVirtualKeyEx(code, 3, GetKeyboardLayout((DWORD)NULL))) & 0x80) == 0x80);
+ }
+}
+
+inline char Poller::isWinNT()
+{
+ return (platformID_ == VER_PLATFORM_WIN32_NT);
+}
+
+inline char Poller::sendInput(unsigned char scancode, unsigned char pressed, int *lengthArrayINPUT)
+{
+ DWORD keyEvent = 0;
+ DWORD extended = 0;
+
+ if (scancode > 0)
+ {
+ if (pressed == 0)
+ {
+ keyEvent = KEYEVENTF_KEYUP;
+ }
+
+ if (scancode & 0x80)
+ {
+ scancode &= ~0x80;
+ extended = KEYEVENTF_EXTENDEDKEY;
+ }
+
+ pKey_[*lengthArrayINPUT].ki.wScan = (WORD) scancode;
+ pKey_[*lengthArrayINPUT].ki.dwFlags = (DWORD) (keyEvent | KEYEVENTF_SCANCODE | extended);
+ (*lengthArrayINPUT)++;
+ }
+
+
+ if (*lengthArrayINPUT > 0) {
+ // FIXME: Remove me.
+ logTest("Poller::sendInput", "length Input [%d] event: %s", *lengthArrayINPUT,
+ pressed == 1 ? "KeyPress": "KeyRelease");
+
+ if (SendInput(*lengthArrayINPUT, pKey_, sizeof(INPUT)) == 0)
+ {
+ logTest("Poller::sendInput", "Failed SendInput, event: %s", pressed == 1 ? "KeyPress": "KeyRelease");
+ *lengthArrayINPUT = 0;
+ return 0;
+ }
+
+ *lengthArrayINPUT = 0;
+ }
+
+ return 1;
+}
+#endif /* Win32Poller_H */
+
+#endif /* __CYGWIN32__ */
diff --git a/nxcompshad/src/X11.cpp b/nxcompshad/src/X11.cpp
new file mode 100644
index 000000000..3643df731
--- /dev/null
+++ b/nxcompshad/src/X11.cpp
@@ -0,0 +1,1598 @@
+/**************************************************************************/
+/* */
+/* 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
+
+#if !defined(__CYGWIN32__) && !defined(WIN32)
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+
+#include <nx-X11/Xlibint.h>
+#include <nx-X11/Xproto.h>
+#include <nx-X11/keysym.h>
+#include "X11/include/XTest_nxcompshad.h"
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "Poller.h"
+#include "Logger.h"
+#include "Shadow.h"
+
+#define ROUNDUP(nbytes, pad) ((((nbytes) + ((pad)-1)) / (pad)) * ((pad)>>3))
+
+#undef TRANSLATE_KEYCODES
+#define TRANSLATE_ALWAYS
+
+typedef struct {
+ KeySym *map;
+ KeyCode minKeyCode,
+ maxKeyCode;
+ int mapWidth;
+} KeySymsRec, *KeySymsPtr;
+
+extern KeySymsPtr NXShadowKeymap;
+
+typedef struct _KeyPressed
+{
+ KeyCode keyRcvd;
+ KeyCode keySent;
+ struct _KeyPressed *next;
+} KeyPressedRec;
+
+static KeyPressedRec *shadowKeyPressedPtr = NULL;
+
+static KeySym *shadowKeysyms = NULL;
+static KeySym *masterKeysyms = NULL;
+
+static KeySym *shadowKeymap = NULL;
+
+static int shadowMinKey, shadowMaxKey, shadowMapWidth;
+static int masterMinKey, masterMaxKey, masterMapWidth;
+
+static int leftShiftOn = 0;
+static int rightShiftOn = 0;
+static int modeSwitchOn = 0;
+static int level3ShiftOn = 0;
+static int altROn = 0;
+
+static int sentFakeLShiftPress = 0;
+static int sentFakeLShiftRelease = 0;
+static int sentFakeRShiftRelease = 0;
+static int sentFakeModeSwitchPress = 0;
+static int sentFakeModeSwitchRelease = 0;
+static int sentFakeLevel3ShiftPress = 0;
+static int sentFakeLevel3ShiftRelease = 0;
+static int sentFakeAltRRelease = 0;
+
+static int shmInitTrap = 0;
+
+Poller::Poller(Input *input, Display *display, int depth) : CorePoller(input, display)
+{
+ logTrace("Poller::Poller");
+
+ display_ = NULL;
+ shadowDisplayName_ = input -> getShadowDisplayName();
+
+ tmpBuffer_ = NULL;
+
+ xtestExtension_ = -1;
+ shmExtension_ = -1;
+ randrExtension_ = -1;
+ damageExtension_ = -1;
+
+ shadowDisplayUid_ = -1;
+
+ image_ = NULL;
+
+ shminfo_ = NULL;
+}
+
+Poller::~Poller()
+{
+ logTrace("Poller::~Poller");
+
+ if (shmExtension_ == 1)
+ {
+ XShmDetach(display_, shminfo_);
+ XDestroyImage(image_);
+ shmdt(shminfo_ -> shmaddr);
+ shmctl(shminfo_ -> shmid, IPC_RMID, 0);
+ }
+
+ if (shminfo_ != NULL)
+ {
+ delete shminfo_;
+
+ shminfo_ = NULL;
+ }
+
+ if (display_ != NULL)
+ {
+ XCloseDisplay(display_);
+ }
+
+ if (tmpBuffer_ != NULL && shmExtension_ != -1 && damageExtension_ == 1)
+ {
+ XFree(tmpBuffer_);
+
+ tmpBuffer_ = NULL;
+ }
+}
+
+int Poller::init()
+{
+ logTrace("Poller::init");
+
+ if (display_ == NULL)
+ {
+ display_ = XOpenDisplay(shadowDisplayName_);
+
+ setShadowDisplay(display_);
+ }
+
+ logTest("Poller::init:" ,"Shadow display [%p] name [%s].", (Display *) display_, shadowDisplayName_);
+
+ if (display_ == NULL)
+ {
+ logTest("Poller::init", "Failed to connect to display [%s].", shadowDisplayName_ ? shadowDisplayName_ : "");
+
+ return -1;
+ }
+
+ setRootSize();
+
+ logTest("Poller::init", "Screen geometry is [%d, %d] depth is [%d] bpl [%d] bpp [%d].",
+ width_, height_, depth_, bpl_, bpp_);
+
+ xtestInit();
+
+ shmInit();
+
+ randrInit();
+
+ damageInit();
+
+ return CorePoller::init();
+}
+
+int Poller::updateShadowFrameBuffer(void)
+{
+ if (shmExtension_ == 1)
+ {
+ if (XShmGetImage(display_, DefaultRootWindow(display_), image_, 0, 0, AllPlanes) == 0)
+ {
+ logDebug("Poller::updateShadowFrameBuffer", "XShmGetImage failed!");
+
+ return -1;
+ }
+ }
+ else
+ {
+ image_ = XGetImage(display_, DefaultRootWindow(display_), 0, 0, width_,
+ height_, AllPlanes, ZPixmap);
+
+ if (image_ == NULL)
+ {
+ logDebug("Poller::updateShadowFrameBuffer", "XGetImage failed!");
+
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+char *Poller::getRect(XRectangle r)
+{
+ logTrace("Poller::getRect");
+
+ logDebug("Poller::getRect", "Going to retrive rectangle [%d, %d, %d, %d].",
+ r.x, r.y, r.width, r.height);
+
+ if (shmExtension_ == 1)
+ {
+ if (damageExtension_ == 1)
+ {
+ image_ -> width = r.width;
+ image_ -> height = r.height;
+
+ image_ -> bytes_per_line = ROUNDUP((image_ -> bits_per_pixel * image_ -> width), image_ -> bitmap_pad);
+
+ if (XShmGetImage(display_, DefaultRootWindow(display_), image_, r.x, r.y, AllPlanes) == 0)
+ {
+ logDebug("Poller::getRect", "XShmGetImage failed!");
+
+ return NULL;
+ }
+
+ tmpBuffer_ = image_ -> data;
+ }
+ else
+ {
+ image_ -> width = r.width;
+ image_ -> height = r.height;
+
+ image_ -> bytes_per_line = ROUNDUP((image_ -> bits_per_pixel * image_ -> width), image_ -> bitmap_pad);
+
+ if (XShmGetImage(display_, DefaultRootWindow(display_), image_, r.x, r.y, AllPlanes) == 0)
+ {
+ logDebug("Poller::getRect", "XShmGetImage failed!");
+ }
+
+ tmpBuffer_ = image_ -> data;
+ }
+ }
+ else
+ {
+ if (tmpBuffer_)
+ {
+ XFree(tmpBuffer_);
+ tmpBuffer_ = NULL;
+ }
+
+ image_ = XGetImage(display_, DefaultRootWindow(display_), r.x, r.y, r.width, r.height, AllPlanes, ZPixmap);
+
+ if (image_ == NULL)
+ {
+ logError("Poller::getRect", ESET(ENOMSG));
+
+ return NULL;
+ }
+
+ tmpBuffer_ = image_ -> data;
+
+ if (image_ -> obdata)
+ {
+ XFree(image_ -> obdata);
+ }
+
+ XFree(image_);
+
+ image_ = NULL;
+ }
+
+ return tmpBuffer_;
+}
+
+void Poller::shmInit(void)
+{
+ int major, minor;
+ int pixmaps;
+
+ logTest("Poller::shmInit", "Added shmExtension_ [%d].", shmExtension_);
+
+ if (shmExtension_ >= 0)
+ {
+ logDebug("Poller::shmInit", "Called with shared memory already initialized.");
+
+ if (shmInitTrap == 0)
+ {
+ return;
+ }
+ }
+
+ if (shmExtension_ < 0 && NXShadowOptions.optionShmExtension == 0)
+ {
+ shmExtension_ = 0;
+
+ logUser("Poller::shmInit: Disabling use of MIT-SHM extension.\n");
+
+ return;
+ }
+
+ if (XShmQueryVersion(display_, &major, &minor, &pixmaps) == 0)
+ {
+ logDebug("Poller::shmInit", "MIT_SHM: Shared memory extension not available.");
+
+ shmExtension_ = 0;
+ }
+ else
+ {
+ logDebug("Poller::shmInit", "MIT_SHM: Shared memory extension available.");
+
+ if (shminfo_ != NULL)
+ {
+ destroyShmImage();
+ }
+
+ shminfo_ = (XShmSegmentInfo* ) new XShmSegmentInfo;
+
+ if (shminfo_ == NULL)
+ {
+ logError("Poller::shmInit", ESET(ENOMEM));
+
+ shmExtension_ = 0;
+
+ return;
+ }
+
+ image_ = (XImage *)XShmCreateImage(display_, display_ -> screens[0].root_visual, depth_, ZPixmap,
+ NULL, shminfo_, width_, height_);
+
+ if (image_ == NULL)
+ {
+ logError("Poller::shmInit", ESET(ENOMSG));
+
+ shmExtension_ = 0;
+
+ return;
+ }
+
+ shadowDisplayUid_ = NXShadowOptions.optionShadowDisplayUid;
+
+ logDebug("Poller::shmInit", "Master X server uid [%d].", NXShadowOptions.optionShadowDisplayUid);
+
+ shminfo_ -> shmid = shmget(IPC_PRIVATE, image_ -> bytes_per_line * image_ -> height, IPC_CREAT | 0666);
+
+ if (shminfo_ -> shmid < 0)
+ {
+ logDebug("Poller::shmInit", "kernel id error.");
+
+ shmExtension_ = 0;
+
+ return;
+ }
+
+ logDebug("Poller::shmInit", "Created shm segment with shmid [%d].", shminfo_ -> shmid);
+
+ shminfo_ -> shmaddr = (char *)shmat(shminfo_ -> shmid, 0, 0);
+
+ if (shminfo_ -> shmaddr < 0)
+ {
+ logWarning("Poller::shmInit", "Couldn't attach to shm segment.");
+ }
+
+ logDebug("Poller::shmInit", "shminfo_ -> shmaddr [%p].", shminfo_ -> shmaddr);
+
+ image_ -> data = shminfo_ -> shmaddr;
+
+ shminfo_ -> readOnly = 0;
+
+ if (XShmAttach(display_, shminfo_) == 0)
+ {
+ logDebug("Poller::shmInit", "XShmAttach failed.");
+
+ shmExtension_ = 0;
+
+ return;
+ }
+
+ //
+ // Mark the shm segment to be destroyed after
+ // the last process detach. Let the X server
+ // complete the X_ShmAttach request, before.
+ //
+
+ XSync(display_, 0);
+
+ struct shmid_ds ds;
+
+ shmctl(shminfo_ -> shmid, IPC_STAT, &ds);
+
+ if (shadowDisplayUid_ != -1)
+ {
+ ds.shm_perm.uid = (ushort) shadowDisplayUid_;
+ }
+ else
+ {
+ logWarning("Poller::shmInit", "Couldn't set uid for shm segment.");
+ }
+
+ ds.shm_perm.mode = 0600;
+
+ shmctl(shminfo_ -> shmid, IPC_SET, &ds);
+
+ shmctl(shminfo_ -> shmid, IPC_STAT, &ds);
+
+ shmctl(shminfo_ -> shmid, IPC_RMID, 0);
+
+ logDebug("Poller::shmInit", "Number of attaches to shm segment [%d] are [%d].\n",
+ shminfo_ -> shmid, (int) ds.shm_nattch);
+
+ if (ds.shm_nattch > 2)
+ {
+ logWarning("Poller::shmInit", "More than two attaches to the shm segment.");
+
+ destroyShmImage();
+
+ shmExtension_ = 0;
+
+ return;
+ }
+
+ shmExtension_ = 1;
+ }
+}
+
+void Poller::keymapShadowInit(Display *display)
+{
+ int i, len;
+ CARD32 *map;
+
+ if (NXShadowKeymap != NULL)
+ {
+ shadowMinKey = NXShadowKeymap -> minKeyCode;
+ shadowMaxKey = NXShadowKeymap -> maxKeyCode;
+ shadowMapWidth = NXShadowKeymap -> mapWidth;
+
+ len = (shadowMaxKey - shadowMinKey + 1) * shadowMapWidth;
+
+ map = (CARD32 *) NXShadowKeymap -> map;
+
+ if (shadowKeymap != NULL)
+ {
+ free(shadowKeymap);
+ }
+
+ shadowKeymap = (KeySym *) malloc(len * sizeof(KeySym));
+
+ if (shadowKeymap != NULL)
+ {
+ for (i = 0; i < len; i++)
+ {
+ shadowKeymap[i] = map[i];
+ }
+
+ shadowKeysyms = shadowKeymap;
+ }
+ }
+
+ if (shadowKeysyms == NULL)
+ {
+ XDisplayKeycodes(display, &shadowMinKey, &shadowMaxKey);
+
+ shadowKeysyms = XGetKeyboardMapping(display, shadowMinKey, shadowMaxKey - shadowMinKey + 1,
+ &shadowMapWidth);
+ }
+
+ #ifdef DEBUG
+ if (shadowKeysyms != NULL)
+ {
+ for (i = 0; i < (shadowMaxKey - shadowMinKey + 1) * shadowMapWidth; i++)
+ {
+ if (i % shadowMapWidth == 0)
+ {
+ logDebug("Poller::keymapShadowInit", "keycode [%d]", (int) (i / shadowMapWidth));
+ }
+
+ logDebug("\tkeysym", " [%x] [%s]", (unsigned int) shadowKeysyms[i], XKeysymToString(shadowKeysyms[i]));
+ }
+ }
+ #endif
+}
+
+void Poller::keymapMasterInit()
+{
+ XDisplayKeycodes(display_, &masterMinKey, &masterMaxKey);
+
+ masterKeysyms = XGetKeyboardMapping(display_, masterMinKey, masterMaxKey - masterMinKey + 1,
+ &masterMapWidth);
+
+ #ifdef DEBUG
+ if (masterKeysyms != NULL)
+ {
+ for (int i = 0; i < (masterMaxKey - masterMinKey + 1) * masterMapWidth; i++)
+ {
+ if (i % masterMapWidth == 0)
+ {
+ logDebug("Poller::keymapMasterInit", "keycode [%d]", (int) (i / masterMapWidth));
+ }
+
+ logDebug("\tkeysym", " [%x] [%s]", (unsigned int) masterKeysyms[i], XKeysymToString(masterKeysyms[i]));
+ }
+ }
+ #endif
+}
+
+KeySym Poller::keymapKeycodeToKeysym(KeyCode keycode, KeySym *keysyms,
+ int minKey, int mapWidth, int col)
+{
+ int index = ((keycode - minKey) * mapWidth) + col;
+ return keysyms[index];
+}
+
+KeyCode Poller::keymapKeysymToKeycode(KeySym keysym, KeySym *keysyms,
+ int minKey, int maxKey, int mapWidth, int *col)
+{
+ for (int i = 0; i < (maxKey - minKey + 1) * mapWidth; i++)
+ {
+ if (keysyms[i] == keysym)
+ {
+ *col = i % mapWidth;
+ return i / mapWidth + minKey;
+ }
+ }
+ return 0;
+}
+
+KeyCode Poller::translateKeysymToKeycode(KeySym keysym, int *col)
+{
+ KeyCode keycode;
+
+ keycode = keymapKeysymToKeycode(keysym, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, col);
+
+ if (keycode == 0)
+ {
+ if (((keysym >> 8) == 0) && (keysym >= XK_a) && (keysym <= XK_z))
+ {
+ /*
+ * The master session has a Solaris keyboard.
+ */
+
+ keysym -= XK_a - XK_A;
+
+ keycode = keymapKeysymToKeycode(keysym, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, col);
+ }
+ else if (keysym == XK_Shift_R)
+ {
+ keysym = XK_Shift_L;
+
+ keycode = keymapKeysymToKeycode(keysym, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, col);
+ }
+ else if (keysym == XK_Shift_L)
+ {
+ keysym = XK_Shift_R;
+
+ keycode = keymapKeysymToKeycode(keysym, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, col);
+ }
+ else if (keysym == XK_ISO_Level3_Shift)
+ {
+ keysym = XK_Mode_switch;
+
+ if ((keycode = keymapKeysymToKeycode(keysym, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, col)) == 0)
+ {
+ keysym = XK_Alt_R;
+
+ keycode = keymapKeysymToKeycode(keysym, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, col);
+ }
+ }
+ else if (keysym == XK_Alt_R)
+ {
+ keysym = XK_ISO_Level3_Shift;
+
+ if ((keycode = keymapKeysymToKeycode(keysym, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, col)) == 0)
+ {
+ keysym = XK_Mode_switch;
+
+ keycode = keymapKeysymToKeycode(keysym, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, col);
+ }
+ }
+ }
+ return keycode;
+}
+
+Bool Poller::checkModifierKeys(KeySym keysym, Bool isKeyPress)
+{
+ switch (keysym)
+ {
+ case XK_Shift_L:
+ leftShiftOn = isKeyPress;
+ return True;
+ case XK_Shift_R:
+ rightShiftOn = isKeyPress;
+ return True;
+ case XK_Mode_switch:
+ modeSwitchOn = isKeyPress;
+ return True;
+ case XK_ISO_Level3_Shift:
+ level3ShiftOn = isKeyPress;
+ return True;
+ case XK_Alt_R:
+ altROn = isKeyPress;
+ return True;
+ default:
+ return False;
+ }
+}
+
+void Poller::sendFakeModifierEvents(int pos, Bool skip)
+{
+ KeySym fakeKeysym;
+ int col;
+
+ if ((!leftShiftOn && !rightShiftOn) &&
+ (!modeSwitchOn && !level3ShiftOn && !altROn))
+ {
+ if (pos == 1 || pos == 3)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Shift_L, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 1, 0);
+ sentFakeLShiftPress = 1;
+ }
+ if (pos == 2 || pos == 3)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_ISO_Level3_Shift, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+
+ if (fakeKeysym == 0)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Mode_switch, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ sentFakeModeSwitchPress = 1;
+ }
+ else
+ {
+ sentFakeLevel3ShiftPress = 1;
+ }
+
+ XTestFakeKeyEvent(display_, fakeKeysym, 1, 0);
+ }
+ }
+
+ else if ((leftShiftOn || rightShiftOn) &&
+ (!modeSwitchOn && !level3ShiftOn && !altROn))
+ {
+ if ((pos == 0 && !skip) || pos == 2)
+ {
+ if (leftShiftOn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Shift_L, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeLShiftRelease = 1;
+ }
+ if (rightShiftOn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Shift_R, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeRShiftRelease = 1;
+ }
+ }
+ if (pos == 2 || pos ==3)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_ISO_Level3_Shift, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+
+ if (fakeKeysym == 0)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Mode_switch, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ sentFakeModeSwitchPress = 1;
+ }
+ else
+ {
+ sentFakeLevel3ShiftPress = 1;
+ }
+
+ XTestFakeKeyEvent(display_, fakeKeysym, 1, 0);
+ }
+ }
+
+ else if ((!leftShiftOn && !rightShiftOn) &&
+ (modeSwitchOn || level3ShiftOn || altROn))
+ {
+ if (pos == 1 || pos == 3)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Shift_L, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 1, 0);
+ sentFakeLShiftPress = 1;
+ }
+ if (pos == 0 || pos == 1)
+ {
+ if (modeSwitchOn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Mode_switch, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeModeSwitchRelease = 1;
+ }
+ if (level3ShiftOn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_ISO_Level3_Shift, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeLevel3ShiftRelease = 1;
+ }
+ if (altROn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Alt_R, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeAltRRelease = 1;
+ }
+ }
+ }
+
+ else if ((leftShiftOn || rightShiftOn) &&
+ (modeSwitchOn || level3ShiftOn || altROn))
+ {
+ if (pos == 0 || pos == 2)
+ {
+ if (leftShiftOn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Shift_L, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeLShiftRelease = 1;
+ }
+ if (rightShiftOn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Shift_R, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeRShiftRelease = 1;
+ }
+ }
+ if (pos == 0 || pos == 1)
+ {
+ if (modeSwitchOn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Mode_switch, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeModeSwitchRelease = 1;
+ }
+ if (level3ShiftOn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_ISO_Level3_Shift, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeLevel3ShiftRelease = 1;
+ }
+ if (altROn)
+ {
+ fakeKeysym = keymapKeysymToKeycode(XK_Alt_R, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+ sentFakeAltRRelease = 1;
+ }
+ }
+ }
+}
+
+void Poller::cancelFakeModifierEvents()
+{
+ KeySym fakeKeysym;
+ int col;
+
+ if (sentFakeLShiftPress)
+ {
+ logTest("Poller::handleKeyboardEvent", "Fake Shift_L key press event has been sent");
+ logTest("Poller::handleKeyboardEvent", "Sending fake Shift_L key release event");
+
+ fakeKeysym = keymapKeysymToKeycode(XK_Shift_L, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+
+ sentFakeLShiftPress = 0;
+ }
+
+ if (sentFakeLShiftRelease)
+ {
+ logTest("Poller::handleKeyboardEvent", "Fake Shift_L key release event has been sent");
+ logTest("Poller::handleKeyboardEvent", "Sending fake Shift_L key press event");
+
+ fakeKeysym = keymapKeysymToKeycode(XK_Shift_L, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 1, 0);
+
+ sentFakeLShiftRelease = 0;
+ }
+
+ if (sentFakeRShiftRelease)
+ {
+ logTest("Poller::handleKeyboardEvent", "Fake Shift_R key release event has been sent");
+ logTest("Poller::handleKeyboardEvent", "Sending fake Shift_R key press event");
+
+ fakeKeysym = keymapKeysymToKeycode(XK_Shift_R, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 1, 0);
+
+ sentFakeRShiftRelease = 0;
+ }
+
+ if (sentFakeModeSwitchPress)
+ {
+ logTest("Poller::handleKeyboardEvent", "Fake Mode_switch key press event has been sent");
+ logTest("Poller::handleKeyboardEvent", "Sending fake Mode_switch key release event");
+
+ fakeKeysym = keymapKeysymToKeycode(XK_Mode_switch, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+
+ sentFakeModeSwitchPress = 0;
+ }
+
+ if (sentFakeModeSwitchRelease)
+ {
+ logTest("Poller::handleKeyboardEvent", "Fake Mode_switch key release event has been sent");
+ logTest("Poller::handleKeyboardEvent", "Sending Mode_switch key press event");
+
+ fakeKeysym = keymapKeysymToKeycode(XK_Mode_switch, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 1, 0);
+
+ sentFakeModeSwitchRelease = 0;
+ }
+
+ if (sentFakeLevel3ShiftPress)
+ {
+ logTest("Poller::handleKeyboardEvent", "Fake ISO_Level3_Shift key press event has been sent");
+ logTest("Poller::handleKeyboardEvent", "Sending fake ISO_Level3_Shift key release event");
+
+ fakeKeysym = keymapKeysymToKeycode(XK_ISO_Level3_Shift, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 0, 0);
+
+ sentFakeLevel3ShiftPress = 0;
+ }
+
+ if (sentFakeLevel3ShiftRelease)
+ {
+ logTest("Poller::handleKeyboardEvent", "Fake ISO_Level3_Shift key release event has been sent");
+ logTest("Poller::handleKeyboardEvent", "Sending fake ISO_Level3_Shift key press event");
+
+ fakeKeysym = keymapKeysymToKeycode(XK_ISO_Level3_Shift, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 1, 0);
+
+ sentFakeLevel3ShiftRelease = 0;
+ }
+
+ if (sentFakeAltRRelease)
+ {
+ logTest("Poller::handleKeyboardEvent", "Fake XK_Alt_R key release event has been sent");
+ logTest("Poller::handleKeyboardEvent", "Sending fake XK_Alt_R key press event");
+
+ fakeKeysym = keymapKeysymToKeycode(XK_Alt_R, masterKeysyms, masterMinKey,
+ masterMaxKey, masterMapWidth, &col);
+ XTestFakeKeyEvent(display_, fakeKeysym, 1, 0);
+
+ sentFakeAltRRelease = 0;
+ }
+}
+
+Bool Poller::keyIsDown(KeyCode keycode)
+{
+ KeyPressedRec *downKey;
+
+ downKey = shadowKeyPressedPtr;
+
+ while (downKey)
+ {
+ if (downKey -> keyRcvd == keycode)
+ {
+ return True;
+ }
+ downKey = downKey -> next;
+ }
+
+ return False;
+}
+
+void Poller::addKeyPressed(KeyCode received, KeyCode sent)
+{
+ KeyPressedRec *downKey;
+
+ if (!keyIsDown(received))
+ {
+ if (shadowKeyPressedPtr == NULL)
+ {
+ shadowKeyPressedPtr = (KeyPressedRec *) malloc(sizeof(KeyPressedRec));
+
+ shadowKeyPressedPtr -> keyRcvd = received;
+ shadowKeyPressedPtr -> keySent = sent;
+ shadowKeyPressedPtr -> next = NULL;
+ }
+ else
+ {
+ downKey = shadowKeyPressedPtr;
+
+ while (downKey -> next != NULL)
+ {
+ downKey = downKey -> next;
+ }
+
+ downKey -> next = (KeyPressedRec *) malloc(sizeof(KeyPressedRec));
+
+ downKey -> next -> keyRcvd = received;
+ downKey -> next -> keySent = sent;
+ downKey -> next -> next = NULL;
+ }
+ }
+}
+
+KeyCode Poller::getKeyPressed(KeyCode received)
+{
+ KeyCode sent;
+ KeyPressedRec *downKey;
+ KeyPressedRec *tempKey;
+
+ if (shadowKeyPressedPtr != NULL)
+ {
+ if (shadowKeyPressedPtr -> keyRcvd == received)
+ {
+ sent = shadowKeyPressedPtr -> keySent;
+
+ tempKey = shadowKeyPressedPtr;
+ shadowKeyPressedPtr = shadowKeyPressedPtr -> next;
+ free(tempKey);
+
+ return sent;
+ }
+ else
+ {
+ downKey = shadowKeyPressedPtr;
+
+ while (downKey -> next != NULL)
+ {
+ if (downKey -> next -> keyRcvd == received)
+ {
+ sent = downKey -> next -> keySent;
+
+ tempKey = downKey -> next;
+ downKey -> next = downKey -> next -> next;
+ free(tempKey);
+
+ return sent;
+ }
+ else
+ {
+ downKey = downKey -> next;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void Poller::handleKeyboardEvent(Display *display, XEvent *event)
+{
+ if (xtestExtension_ == 0 || display_ == 0)
+ {
+ return;
+ }
+
+ logTest("Poller::handleKeyboardEvent", "Handling event at [%p]", event);
+
+#ifdef TRANSLATE_ALWAYS
+
+ KeyCode keycode;
+ KeySym keysym;
+
+ int col = 0;
+
+ Bool isKeyPress = False;
+ Bool isModifier = False;
+ Bool isShiftComb = False;
+ Bool skip = False;
+
+ if (event -> type == KeyPress)
+ {
+ isKeyPress = True;
+ }
+
+ if (shadowKeysyms == NULL)
+ {
+ keymapShadowInit(event -> xkey.display);
+ }
+
+ if (masterKeysyms == NULL)
+ {
+ keymapMasterInit();
+ }
+
+ if (shadowKeysyms == NULL || masterKeysyms == NULL)
+ {
+ logTest("Poller::handleKeyboardEvent", "Unable to initialize keymaps. Do not translate");
+
+ keycode = event -> xkey.keycode;
+
+ goto SendKeycode;
+ }
+
+ keysym = keymapKeycodeToKeysym(event -> xkey.keycode, shadowKeysyms,
+ shadowMinKey, shadowMapWidth, 0);
+
+ isModifier = checkModifierKeys(keysym, isKeyPress);
+
+ if (event -> type == KeyRelease)
+ {
+ KeyCode keycodeToSend;
+
+ keycodeToSend = getKeyPressed(event -> xkey.keycode);
+
+ if (keycodeToSend)
+ {
+ keycode = keycodeToSend;
+
+ goto SendKeycode;
+ }
+ }
+
+ /*
+ * Convert case for Solaris keyboard.
+ */
+
+ if (((keysym >> 8) == 0) && (keysym >= XK_A) && (keysym <= XK_Z))
+ {
+ if (!leftShiftOn && !rightShiftOn)
+ {
+ keysym += XK_a - XK_A;
+ }
+ else
+ {
+ skip = True;
+ }
+ }
+
+ if (!isModifier)
+ {
+ if ((leftShiftOn || rightShiftOn) &&
+ (!modeSwitchOn && !level3ShiftOn && !altROn) &&
+ !skip)
+ {
+ KeySym tempKeysym = keymapKeycodeToKeysym(event -> xkey.keycode, shadowKeysyms,
+ shadowMinKey, shadowMapWidth, 1);
+
+ if (tempKeysym == 0)
+ {
+ isShiftComb = True;
+ }
+ else
+ {
+ keysym = tempKeysym;
+ }
+ }
+ else if ((!leftShiftOn && !rightShiftOn) &&
+ (modeSwitchOn || level3ShiftOn || altROn))
+ {
+ keysym = keymapKeycodeToKeysym(event -> xkey.keycode, shadowKeysyms,
+ shadowMinKey, shadowMapWidth, 2);
+ }
+ else if ((leftShiftOn || rightShiftOn) &&
+ (modeSwitchOn || level3ShiftOn || altROn))
+ {
+ keysym = keymapKeycodeToKeysym(event -> xkey.keycode, shadowKeysyms,
+ shadowMinKey, shadowMapWidth, 3);
+ }
+ }
+
+ if (keysym == 0)
+ {
+ logTest("Poller::handleKeyboardEvent", "Null keysym. Return");
+
+ return;
+ }
+
+ logTest("Poller::handleKeyboardEvent", "keysym [%x] [%s]",
+ (unsigned int)keysym, XKeysymToString(keysym));
+
+ if (keysym == XK_Mode_switch)
+ {
+ keysym = XK_ISO_Level3_Shift;
+ }
+
+ keycode = translateKeysymToKeycode(keysym, &col);
+
+ if (keycode == 0)
+ {
+ logTest("Poller::handleKeyboardEvent", "No keycode found for keysym [%x] [%s]. Return",
+ (unsigned int)keysym, XKeysymToString(keysym));
+ return;
+ }
+
+ logTest("Poller::handleKeyboardEvent", "keycode [%d] translated into keycode [%d]",
+ (int)event -> xkey.keycode, (unsigned int)keycode);
+
+ if (event -> type == KeyPress)
+ {
+ addKeyPressed(event -> xkey.keycode, keycode);
+ }
+
+ /*
+ * Send fake modifier events.
+ */
+
+ if (!isModifier && isShiftComb == False)
+ {
+ sendFakeModifierEvents(col, ((keysym >> 8) == 0) && (keysym >= XK_A) && (keysym <= XK_Z));
+ }
+
+SendKeycode:
+
+ /*
+ * Send the event.
+ */
+
+ XTestFakeKeyEvent(display_, keycode, isKeyPress, 0);
+
+ /*
+ * Check if fake modifier events have been sent.
+ */
+
+ cancelFakeModifierEvents();
+
+#else // TRANSLATE_ALWAYS
+
+ //
+ // Use keysyms to translate keycodes across different
+ // keyboard models. Unuseful when both keyboards have
+ // same keycodes (e.g. both are pc keyboards).
+ //
+
+ #ifdef TRANSLATE_KEYCODES
+
+ KeyCode keycode = XKeysymToKeycode(display_, XK_A);
+
+ if (XKeysymToKeycode(event -> xkey.display, XK_A) != keycode)
+ {
+ KeySym keysym = XKeycodeToKeysym(event -> xkey.display, event -> xkey.keycode, 0);
+
+ if (keysym == XK_Mode_switch || keysym == XK_ISO_Level3_Shift)
+ {
+ logUser("Poller::handleKeyboardEvent: keysym [%x].\n", (unsigned int)keysym);
+
+ if (XKeycodeToKeysym(display_, 113, 0) == XK_ISO_Level3_Shift ||
+ (XKeycodeToKeysym(display_, 124, 0) == XK_ISO_Level3_Shift))
+ {
+ event -> xkey.keycode = 113;
+ }
+ else
+ {
+ event -> xkey.keycode = XKeysymToKeycode(display_, XK_Mode_switch);
+ }
+
+ logUser("Poller::handleKeyboardEvent: keycode translated to [%x].\n", (unsigned int)event -> xkey.keycode);
+ }
+ else
+ {
+ event -> xkey.keycode = XKeysymToKeycode(display_, keysym);
+ }
+ }
+
+ #endif // TRANSLATE_KEYCODES
+
+ if (event -> type == KeyPress)
+ {
+ XTestFakeKeyEvent(display_, event -> xkey.keycode, 1, 0);
+ }
+ else if (event -> type == KeyRelease)
+ {
+ XTestFakeKeyEvent(display_, event -> xkey.keycode, 0, 0);
+ }
+
+#endif // TRANSLATE_ALWAYS
+}
+
+void Poller::handleWebKeyboardEvent(KeySym keysym, Bool isKeyPress)
+{
+ KeyCode keycode;
+ int col;
+
+ if (masterKeysyms == NULL)
+ {
+ keymapMasterInit();
+ }
+
+ if (masterKeysyms == NULL)
+ {
+ logTest("Poller::handleWebKeyboardEvent", "Unable to initialize keymap");
+
+ return;
+ }
+
+ keycode = translateKeysymToKeycode(keysym, &col);
+
+ if (keycode == 0)
+ {
+ logTest("Poller::handleKeyboardEvent", "No keycode found for keysym [%x] [%s]. Return",
+ (unsigned int)keysym, XKeysymToString(keysym));
+ return;
+ }
+
+ logTest("Poller::handleKeyboardEvent", "keysym [%x] [%s] translated into keycode [%x]",
+ (unsigned int)keysym, XKeysymToString(keysym), (unsigned int)keycode);
+
+ /*
+ * Send fake modifier events.
+ */
+
+ if (!checkModifierKeys(keysym, isKeyPress))
+ {
+ sendFakeModifierEvents(col, False);
+ }
+
+ /*
+ * Send the event.
+ */
+
+ XTestFakeKeyEvent(display_, keycode, isKeyPress, 0);
+
+ /*
+ * Check if fake modifier events have been sent.
+ */
+
+ cancelFakeModifierEvents();
+
+}
+
+void Poller::handleMouseEvent(Display *display, XEvent *event)
+{
+ if (xtestExtension_ == 0 || display_ == 0)
+ {
+ return;
+ }
+
+ if (event -> type == MotionNotify)
+ {
+ XTestFakeMotionEvent(display_, 0, event -> xmotion.x, event -> xmotion.y, 0);
+ }
+ else if (event -> type == ButtonPress)
+ {
+ XTestFakeButtonEvent(display_, event -> xbutton.button, True, 0);
+ }
+ else if (event -> type == ButtonRelease)
+ {
+ XTestFakeButtonEvent(display_, event -> xbutton.button, False, 0);
+ }
+
+ XFlush(display_);
+}
+
+void Poller::setRootSize(void)
+{
+ width_ = WidthOfScreen(DefaultScreenOfDisplay(display_));
+ height_ = HeightOfScreen(DefaultScreenOfDisplay(display_));
+ depth_ = DefaultDepth(display_, DefaultScreen(display_));
+
+ if (depth_ == 8) bpp_ = 1;
+ else if (depth_ == 16) bpp_ = 2;
+ else bpp_ = 4;
+
+ bpl_ = width_ * bpp_;
+}
+
+void Poller::destroyShmImage(void)
+{
+ XShmDetach(display_, shminfo_);
+ XDestroyImage(image_);
+ image_ = NULL;
+
+ shmdt(shminfo_ -> shmaddr);
+ shmctl(shminfo_ -> shmid, IPC_RMID, 0);
+
+ delete shminfo_;
+ shminfo_ = NULL;
+}
+
+void Poller::xtestInit(void)
+{
+ int eventBase;
+ int errorBase;
+ int versionMajor;
+ int versionMinor;
+ int result;
+
+ xtestExtension_ = 0;
+
+ result = XTestQueryExtension(display_, &eventBase, &errorBase, &versionMajor, &versionMinor);
+
+ if (result == 0)
+ {
+ xtestExtension_ = 0;
+
+ logWarning("Poller::xtestInit", "Failed while querying for XTEST extension.");
+ }
+ else
+ {
+ logDebug("Poller::xtestInit", "XTEST version %d.%d.", versionMajor, versionMinor);
+
+ xtestExtension_ = 1;
+ }
+
+ //
+ // Make this client impervious to grabs.
+ //
+
+ if (xtestExtension_ == 1)
+ {
+ XTestGrabControl(display_, 1);
+ }
+}
+
+void Poller::randrInit(void)
+{
+ int randrEventBase;
+ int randrErrorBase;
+
+ if (XRRQueryExtension(display_, &randrEventBase, &randrErrorBase) == 0)
+ {
+ logWarning("Poller::randrInit", "Randr extension not supported on this "
+ "display.");
+
+ randrExtension_ = 0;
+
+ return;
+ }
+
+ XRRSelectInput(display_, DefaultRootWindow(display_),
+ RRScreenChangeNotifyMask);
+
+ randrEventBase_ = randrEventBase;
+
+ randrExtension_ = 1;
+
+ return;
+}
+
+void Poller::damageInit(void)
+{
+ int damageMajorVersion = 0;
+ int damageMinorVersion = 0;
+
+ int damageEventBase = 0;
+ int damageErrorBase = 0;
+
+ if (damageExtension_ >= 0)
+ {
+ logDebug("Poller::damageInit", "Called with damage already initialized.");
+ }
+
+ if (damageExtension_ == 0)
+ {
+ logDebug("Poller::damageInit", "Damage disabled. Skip initialization.");
+
+ return;
+ }
+
+ if (damageExtension_ < 0 && NXShadowOptions.optionDamageExtension == 0)
+ {
+ damageExtension_ = 0;
+
+ logUser("Poller::damageInit: Disabling use of DAMAGE extension.\n");
+
+ return;
+ }
+
+ damageExtension_ = 0;
+
+ mirrorChanges_ = 0;
+
+ if (XDamageQueryExtension(display_, &damageEventBase, &damageErrorBase) == 0)
+ {
+ logUser("Poller::damageInit: DAMAGE not supported.\n");
+
+ return;
+ }
+ #ifdef DEBUG
+ else
+ {
+ fprintf(stderr, "Poller::damageInit: DAMAGE supported. "
+ "Event base [%d] error base [%d].\n", damageEventBase, damageErrorBase);
+ }
+ #endif
+
+ damageEventBase_ = damageEventBase;
+
+ if (XDamageQueryVersion(display_, &damageMajorVersion, &damageMinorVersion) == 0)
+ {
+ logWarning("Poller::damageInit", "Error on querying DAMAGE version.\n");
+
+ damageExtension_ = 0;
+
+ return;
+ }
+ #ifdef DEBUG
+ else
+ {
+ fprintf(stderr, "Poller::damageInit: DAMAGE version %d.%d.\n",
+ damageMajorVersion, damageMinorVersion);
+ }
+ #endif
+
+ damage_ = XDamageCreate(display_, DefaultRootWindow(display_), XDamageReportRawRectangles);
+
+ damageExtension_= 1;
+
+ mirror_ = 1;
+
+ return;
+}
+
+void Poller::getEvents(void)
+{
+ XEvent X;
+
+ if (damageExtension_ == 1)
+ {
+ XDamageSubtract(display_, damage_, None, None);
+ }
+
+ XSync(display_, 0);
+
+ while (XCheckIfEvent(display_, &X, anyEventPredicate, NULL) == 1)
+ {
+ if (randrExtension_ == 1 && (X.type == randrEventBase_ + RRScreenChangeNotify || X.type == ConfigureNotify))
+ {
+ XRRUpdateConfiguration(&X);
+
+ handleRRScreenChangeNotify(&X);
+
+ continue;
+ }
+
+ if (damageExtension_ == 1 && X.type == damageEventBase_ + XDamageNotify)
+ {
+ handleDamageNotify(&X);
+ }
+ }
+
+ if (damageExtension_ == 1)
+ {
+ updateDamagedAreas();
+ }
+
+ XFlush(display_);
+}
+
+void Poller::handleRRScreenChangeNotify(XEvent *X)
+{
+ return;
+}
+
+void Poller::handleDamageNotify(XEvent *X)
+{
+ XDamageNotifyEvent *e = (XDamageNotifyEvent *) X;
+
+ //
+ // e->drawable is the window ID of the damaged window
+ // e->geometry is the geometry of the damaged window
+ // e->area is the bounding rect for the damaged area
+ // e->damage is the damage handle returned by XDamageCreate()
+ //
+
+ #ifdef DEBUG
+ fprintf(stderr, "handleDamageNotify: drawable [%d] damage [%d] geometry [%d][%d][%d][%d] area [%d][%d][%d][%d].\n",
+ (int) e -> drawable, (int) e -> damage, e -> geometry.x, e -> geometry.y,
+ e -> geometry.width, e -> geometry.height, e -> area.x, e -> area.y,
+ e -> area.width, e -> area.height);
+ #endif
+
+ XRectangle rectangle = {e -> area.x, e -> area.y, e -> area.width, e -> area.height};
+
+ XUnionRectWithRegion(&rectangle, lastUpdatedRegion_, lastUpdatedRegion_);
+
+ mirrorChanges_ = 1;
+
+ return;
+}
+
+void Poller::updateDamagedAreas(void)
+{
+ BOX *boxPtr;
+
+ XRectangle rectangle;
+
+ int i;
+ int y;
+
+ for (i = 0; i < lastUpdatedRegion_ -> numRects; i++)
+ {
+ boxPtr = lastUpdatedRegion_ -> rects + i;
+
+ if (shmExtension_ == 1)
+ {
+ image_ -> width = boxPtr -> x2 - boxPtr -> x1;
+ image_ -> height = boxPtr -> y2 - boxPtr -> y1;
+ image_ -> bytes_per_line =
+ ROUNDUP((image_ -> bits_per_pixel * image_ -> width),
+ image_ -> bitmap_pad);
+
+ if (XShmGetImage(display_, DefaultRootWindow(display_), image_,
+ boxPtr -> x1, boxPtr -> y1, AllPlanes) == 0)
+ {
+ logDebug("Poller::updateDamagedAreas", "XShmGetImage failed!");
+
+ return;
+ }
+ }
+ else if (shmExtension_ == 0)
+ {
+ image_ = XGetImage(display_, DefaultRootWindow(display_), boxPtr -> x1,
+ boxPtr -> y1, boxPtr -> x2 - boxPtr -> x1,
+ boxPtr -> y2 - boxPtr -> y1, AllPlanes,
+ ZPixmap);
+
+ if (image_ == NULL)
+ {
+ logDebug("Poller::updateDamagedAreas", "XGetImage failed!");
+
+ return;
+ }
+
+ image_ -> width = boxPtr -> x2 - boxPtr -> x1;
+ image_ -> height = boxPtr -> y2 - boxPtr -> y1;
+ image_ -> bytes_per_line =
+ ROUNDUP((image_ -> bits_per_pixel * image_ -> width),
+ image_ -> bitmap_pad);
+ }
+
+ rectangle.height = 1;
+ rectangle.width = image_ -> width;
+ rectangle.x = boxPtr -> x1;
+ rectangle.y = boxPtr -> y1;
+
+ for (y = 0; y < image_ -> height; y++)
+ {
+ update(image_ -> data + y * image_ -> bytes_per_line, rectangle);
+
+ rectangle.y++;
+ }
+
+ if (shmExtension_ != 1)
+ {
+ XDestroyImage(image_);
+
+ image_ = NULL;
+ }
+ }
+
+ return;
+}
+
+void Poller::getScreenSize(int *w, int *h)
+{
+ *w = WidthOfScreen(DefaultScreenOfDisplay(display_));
+ *h = HeightOfScreen(DefaultScreenOfDisplay(display_));
+}
+
+void Poller::setScreenSize(int *w, int *h)
+{
+ setRootSize();
+
+ shmInitTrap = 1;
+ shmInit();
+ shmInitTrap = 0;
+
+ *w = width_;
+ *h = height_;
+
+ logDebug("Poller::setScreenSize", "New size of screen [%d, %d]", width_, height_);
+}
+
+int anyEventPredicate(Display *display, XEvent *event, XPointer parameter)
+{
+ return 1;
+}
+
+#endif /* !defined(__CYGWIN32__) && !defined(WIN32) */
diff --git a/nxcompshad/src/X11.h b/nxcompshad/src/X11.h
new file mode 100644
index 000000000..87dd31fea
--- /dev/null
+++ b/nxcompshad/src/X11.h
@@ -0,0 +1,139 @@
+/**************************************************************************/
+/* */
+/* 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. */
+/* */
+/**************************************************************************/
+
+#ifndef X11Poller_H
+#define X11Poller_H
+
+#include <nx-X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+#include "X11/include/Xdamage_nxcompshad.h"
+#include "X11/include/Xrandr_nxcompshad.h"
+
+#include "Core.h"
+
+class Poller : public CorePoller
+{
+ public:
+
+ Poller(Input *, Display *display, int = 0);
+
+ ~Poller();
+
+ int init();
+
+ void setRootSize();
+
+ void destroyShmImage();
+
+ void getEvents(void);
+
+ void getScreenSize(int *width, int *height);
+
+ void setScreenSize(int *width, int *height);
+
+ private:
+
+ Display *display_;
+
+ char *shadowDisplayName_;
+
+ int shadowDisplayUid_;
+
+ char *tmpBuffer_;
+
+ char xtestExtension_;
+
+ char shmExtension_;
+
+ char randrExtension_;
+
+ int randrEventBase_;
+
+ char damageExtension_;
+
+ int damageEventBase_;
+
+ Damage damage_;
+
+ Region repair_;
+
+ char damageChanges_;
+
+ XShmSegmentInfo *shminfo_;
+
+ XImage *image_;
+
+ int updateShadowFrameBuffer(void);
+
+ char *getRect(XRectangle);
+
+ void keymapShadowInit(Display *display);
+
+ void keymapMasterInit();
+
+ KeySym keymapKeycodeToKeysym(KeyCode keycode, KeySym *keysyms,
+ int minKey, int per, int col);
+
+ KeyCode keymapKeysymToKeycode(KeySym keysym, KeySym *keysyms,
+ int minKey, int maxKey, int per, int *col);
+
+ KeyCode translateKeysymToKeycode(KeySym keysym, int *col);
+
+ Bool checkModifierKeys(KeySym keysym, Bool isKeyPress);
+
+ void sendFakeModifierEvents(int pos, Bool skip);
+
+ void cancelFakeModifierEvents();
+
+ Bool keyIsDown(KeyCode keycode);
+
+ void addKeyPressed(KeyCode received, KeyCode sent);
+
+ KeyCode getKeyPressed(KeyCode received);
+
+ void handleKeyboardEvent(Display *display, XEvent *);
+
+ void handleWebKeyboardEvent(KeySym keysym, Bool isKeyPress);
+
+ void handleMouseEvent(Display *, XEvent *);
+
+ void xtestInit(void);
+
+ void shmInit(void);
+
+ void randrInit(void);
+
+ void damageInit(void);
+
+ void handleRRScreenChangeNotify(XEvent *);
+
+ void handleDamageNotify(XEvent *);
+
+ void updateDamagedAreas(void);
+};
+
+int anyEventPredicate(Display *display, XEvent *event, XPointer parameter);
+
+#endif /* X11Poller_H */
diff --git a/nxcompshad/src/X11/include/XTest_nxcompshad.h b/nxcompshad/src/X11/include/XTest_nxcompshad.h
new file mode 100644
index 000000000..91a2ba40b
--- /dev/null
+++ b/nxcompshad/src/X11/include/XTest_nxcompshad.h
@@ -0,0 +1,71 @@
+/*
+
+Copyright 1992, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+
+#ifndef _XTEST_H_
+#define _XTEST_H_
+
+#include <nx-X11/Xfuncproto.h>
+
+_XFUNCPROTOBEGIN
+
+Bool XTestQueryExtension(
+ Display* /* dpy */,
+ int* /* event_basep */,
+ int* /* error_basep */,
+ int* /* majorp */,
+ int* /* minorp */
+);
+
+extern int XTestFakeKeyEvent(
+ Display* /* dpy */,
+ unsigned int /* keycode */,
+ Bool /* is_press */,
+ unsigned long /* delay */
+);
+
+extern int XTestFakeButtonEvent(
+ Display* /* dpy */,
+ unsigned int /* button */,
+ Bool /* is_press */,
+ unsigned long /* delay */
+);
+
+extern int XTestFakeMotionEvent(
+ Display* /* dpy */,
+ int /* screen */,
+ int /* x */,
+ int /* y */,
+ unsigned long /* delay */
+);
+
+extern int XTestGrabControl(
+ Display* /* dpy */,
+ Bool /* impervious */
+);
+
+_XFUNCPROTOEND
+
+#endif
diff --git a/nxcompshad/src/X11/include/Xdamage_nxcompshad.h b/nxcompshad/src/X11/include/Xdamage_nxcompshad.h
new file mode 100644
index 000000000..cae3e1c67
--- /dev/null
+++ b/nxcompshad/src/X11/include/Xdamage_nxcompshad.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright © 2003 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file is a reduced version of the header file of
+ * <X11/extensions/Xdamaga.h>
+ *
+ * This copy of code has been introduced to allow a clear namespace
+ * separation between <X11/...> and <nx-X11/...> header files.
+ *
+ * This version of the Xdamage library header file only contains symbols
+ * required by nxcompshad and strictly avoids indirectly including
+ * from an X11 library that is also shipped in nx-X11/lib/.
+ *
+ * When using <X11/extensions/Xdamage.h> instead for inclusion in
+ * nxcompshad, it will attempt pulling in the <X11/extensions/Xfixes.h>
+ * header which in turn will include <X11/Xlib.h>. However, the headers of
+ * the same name from <nx-X11/...> should be used instead.
+ *
+ * FIXME: Once the nxagent Xserver starts using libX11 from X.Org, this
+ * hack can be removed.
+ *
+ * 2015/06/26, Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+ */
+
+
+#ifndef _XDAMAGE_H_
+#define _XDAMAGE_H_
+
+#include <X11/extensions/damagewire.h>
+#include <nx-X11/Xfuncproto.h>
+
+/* from <X11/extensions/Xfixes.h> */
+typedef XID XserverRegion;
+
+#define XDAMAGE_1_1_INTERFACE
+
+typedef XID Damage;
+
+typedef struct {
+ int type; /* event base */
+ unsigned long serial;
+ Bool send_event;
+ Display *display;
+ Drawable drawable;
+ Damage damage;
+ int level;
+ Bool more; /* more events will be delivered immediately */
+ Time timestamp;
+ XRectangle area;
+ XRectangle geometry;
+} XDamageNotifyEvent;
+
+_XFUNCPROTOBEGIN
+
+Bool XDamageQueryExtension (Display *dpy,
+ int *event_base_return,
+ int *error_base_return);
+
+Status XDamageQueryVersion (Display *dpy,
+ int *major_version_return,
+ int *minor_version_return);
+
+Damage
+XDamageCreate (Display *dpy, Drawable drawable, int level);
+
+void
+XDamageSubtract (Display *dpy, Damage damage,
+ XserverRegion repair, XserverRegion parts);
+
+_XFUNCPROTOEND
+
+#endif /* _XDAMAGE_H_ */
diff --git a/nxcompshad/src/X11/include/Xrandr_nxcompshad.h b/nxcompshad/src/X11/include/Xrandr_nxcompshad.h
new file mode 100644
index 000000000..4feb01685
--- /dev/null
+++ b/nxcompshad/src/X11/include/Xrandr_nxcompshad.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2000 Compaq Computer Corporation, Inc.
+ * Copyright © 2002 Hewlett-Packard Company, Inc.
+ * Copyright © 2006 Intel Corporation
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Author: Jim Gettys, HP Labs, Hewlett-Packard, Inc.
+ * Keith Packard, Intel Corporation
+ */
+
+/*
+ * This file is a reduced version of the header file of
+ * <X11/extensions/Xrandr.h>
+ *
+ * This copy of code has been introduced to allow a clear namespace
+ * separation between <X11/...> and <nx-X11/...> header files.
+ *
+ * This version of the Xrandr library header file only contains symbols
+ * required by nxcompshad and strictly avoids indirectly including
+ * from an X11 library that is also shipped in nx-X11/lib/.
+ *
+ * When using <X11/extensions/Xrandr.h> instead for inclusion in
+ * nxcompshad, it will attempt pulling in the <X11/extensions/Xrender.h>
+ * header which in turn will include <X11/Xlib.h>. However, the headers of
+ * the same name from <nx-X11/...> should be used instead.
+ *
+ * FIXME: Once the nxagent Xserver starts using libXrender from X.Org, this
+ * hack can be removed.
+ *
+ * 2015/06/26, Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+ */
+
+#ifndef _XRANDR_H_
+#define _XRANDR_H_
+
+/* from <X11/extensions/randr.h> */
+#define RRScreenChangeNotify 0
+#define RRScreenChangeNotifyMask (1L << 0)
+
+#include <X11/Xfuncproto.h>
+
+_XFUNCPROTOBEGIN
+
+/* internal representation is private to the library */
+typedef struct _XRRScreenConfiguration XRRScreenConfiguration;
+
+Bool XRRQueryExtension (Display *dpy,
+ int *event_base_return,
+ int *error_base_return);
+
+void XRRSelectInput(Display *dpy, Window window, int mask);
+
+
+/*
+ * intended to take RRScreenChangeNotify, or
+ * ConfigureNotify (on the root window)
+ * returns 1 if it is an event type it understands, 0 if not
+ */
+int XRRUpdateConfiguration(XEvent *event);
+_XFUNCPROTOEND
+
+#endif /* _XRANDR_H_ */