Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@590 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/unix/tx/TXImage.cxx b/unix/tx/TXImage.cxx
new file mode 100644
index 0000000..5fa6828
--- /dev/null
+++ b/unix/tx/TXImage.cxx
@@ -0,0 +1,353 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+//
+// TXImage.cxx
+//
+
+
+#include <stdio.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <list>
+#include <rfb/TransImageGetter.h>
+#include <rfb/Exception.h>
+#include <rfb/LogWriter.h>
+#include "TXWindow.h"
+#include "TXImage.h"
+
+using namespace rfb;
+
+static rfb::LogWriter vlog("TXImage");
+
+TXImage::TXImage(Display* d, int width, int height, Visual* vis_, int depth_)
+  : xim(0), dpy(d), vis(vis_), depth(depth_), tig(0), cube(0)
+{
+#ifdef HAVE_MITSHM
+  shminfo = 0;
+#endif
+  width_ = width;
+  height_ = height;
+  for (int i = 0; i < 256; i++)
+    colourMap[i].r = colourMap[i].g = colourMap[i].b = 0;
+
+  if (!vis)
+    vis = DefaultVisual(dpy,DefaultScreen(dpy));
+  if (!depth)
+    depth = DefaultDepth(dpy,DefaultScreen(dpy));
+
+  createXImage();
+  getNativePixelFormat(vis, depth);
+  colourmap = this;
+  format.bpp = 0;  // just make it different to any valid format, so that...
+  setPF(nativePF); // ...setPF() always works
+}
+
+TXImage::~TXImage()
+{
+  if (data != (rdr::U8*)xim->data) delete [] data;
+  destroyXImage();
+  delete tig;
+  delete cube;
+}
+
+void TXImage::resize(int w, int h)
+{
+  if (w == width() && h == height()) return;
+
+  int oldStrideBytes = getStride() * (format.bpp/8);
+  int rowsToCopy = __rfbmin(h, height());
+  int bytesPerRow = __rfbmin(w, width()) * (format.bpp/8);
+  rdr::U8* oldData = 0;
+  bool allocData = false;
+
+  if (data != (rdr::U8*)xim->data) {
+    oldData = (rdr::U8*)data;
+    allocData = true;
+  } else {
+    oldData = new rdr::U8[xim->bytes_per_line * height()];
+    memcpy(oldData, xim->data, xim->bytes_per_line * height());
+  }
+
+  destroyXImage();
+  width_ = w;
+  height_ = h;
+  createXImage();
+
+  if (allocData)
+    data = new rdr::U8[width() * height() * (format.bpp/8)];
+  else
+    data = (rdr::U8*)xim->data;
+
+  int newStrideBytes = getStride() * (format.bpp/8);
+  for (int i = 0; i < rowsToCopy; i++)
+    memcpy((rdr::U8*)data + newStrideBytes * i, oldData + oldStrideBytes * i,
+           bytesPerRow);
+  delete [] oldData;
+}
+
+void TXImage::setPF(const PixelFormat& newPF)
+{
+  if (newPF.equal(format)) return;
+  format = newPF;
+
+  if (data != (rdr::U8*)xim->data) delete [] data;
+  delete tig;
+  tig = 0;
+
+  if (format.equal(nativePF) && format.trueColour) {
+    data = (rdr::U8*)xim->data;
+  } else {
+    data = new rdr::U8[width() * height() * (format.bpp/8)];
+    tig = new TransImageGetter();
+    tig->init(this, nativePF, 0, cube);
+  }
+}
+
+int TXImage::getStride() const
+{
+  if (data == (rdr::U8*)xim->data)
+    return xim->bytes_per_line / (xim->bits_per_pixel / 8);
+  else
+    return width();
+}
+
+void TXImage::put(Window win, GC gc, const rfb::Rect& r)
+{
+  if (r.is_empty()) return;
+  int x = r.tl.x;
+  int y = r.tl.y;
+  int w = r.width();
+  int h = r.height();
+  if (data != (rdr::U8*)xim->data) {
+    rdr::U8* ximDataStart = ((rdr::U8*)xim->data + y * xim->bytes_per_line
+                             + x * (xim->bits_per_pixel / 8));
+    tig->getImage(ximDataStart, r,
+                  xim->bytes_per_line / (xim->bits_per_pixel / 8));
+  }
+#ifdef HAVE_MITSHM
+  if (usingShm()) {
+    XShmPutImage(dpy, win, gc, xim, x, y, x, y, w, h, False);
+    return;
+  }
+#endif
+  XPutImage(dpy, win, gc, xim, x, y, x, y, w, h);
+}
+
+void TXImage::setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs)
+{
+  for (int i = 0; i < nColours; i++) {
+    colourMap[firstColour+i].r = rgbs[i*3];
+    colourMap[firstColour+i].g = rgbs[i*3+1];
+    colourMap[firstColour+i].b = rgbs[i*3+2];
+  }
+}
+
+void TXImage::updateColourMap()
+{
+  tig->setColourMapEntries(0, 0, 0);
+}
+
+void TXImage::lookup(int index, int* r, int* g, int* b)
+{
+  *r = colourMap[index].r;
+  *g = colourMap[index].g;
+  *b = colourMap[index].b;
+}
+
+#ifdef HAVE_MITSHM
+static bool caughtError = false;
+
+static int XShmAttachErrorHandler(Display *dpy, XErrorEvent *error)
+{
+  caughtError = true;
+  return 0;
+}
+
+class TXImageCleanup {
+public:
+  std::list<TXImage*> images;
+  ~TXImageCleanup() {
+    while (!images.empty())
+      delete images.front();
+  }
+};
+
+static TXImageCleanup imageCleanup;
+#endif
+
+void TXImage::createXImage()
+{
+#ifdef HAVE_MITSHM
+  int major, minor;
+  Bool pixmaps;
+
+  if (XShmQueryVersion(dpy, &major, &minor, &pixmaps)) {
+    shminfo = new XShmSegmentInfo;
+
+    xim = XShmCreateImage(dpy, vis, depth, ZPixmap,
+                          0, shminfo, width(), height());
+
+    if (xim) {
+      shminfo->shmid = shmget(IPC_PRIVATE,
+                              xim->bytes_per_line * xim->height,
+                              IPC_CREAT|0777);
+
+      if (shminfo->shmid != -1) {
+        shminfo->shmaddr = xim->data = (char*)shmat(shminfo->shmid, 0, 0);
+
+        if (shminfo->shmaddr != (char *)-1) {
+
+          shminfo->readOnly = False;
+
+          XErrorHandler oldHdlr = XSetErrorHandler(XShmAttachErrorHandler);
+          XShmAttach(dpy, shminfo);
+          XSync(dpy, False);
+          XSetErrorHandler(oldHdlr);
+
+          if (!caughtError) {
+            vlog.debug("Using shared memory XImage");
+            imageCleanup.images.push_back(this);
+            return;
+          }
+
+          shmdt(shminfo->shmaddr);
+        } else {
+          vlog.error("shmat failed");
+          perror("shmat");
+        }
+
+        shmctl(shminfo->shmid, IPC_RMID, 0);
+      } else {
+        vlog.error("shmget failed");
+        perror("shmget");
+      }
+
+      XDestroyImage(xim);
+      xim = 0;
+    } else {
+      vlog.error("XShmCreateImage failed");
+    }
+
+    delete shminfo;
+    shminfo = 0;
+  }
+#endif
+
+  xim = XCreateImage(dpy, vis, depth, ZPixmap,
+                     0, 0, width(), height(), BitmapPad(dpy), 0);
+
+  xim->data = (char*)malloc(xim->bytes_per_line * xim->height);
+  if (!xim->data) {
+    vlog.error("malloc failed");
+    exit(1);
+  }
+}
+
+void TXImage::destroyXImage()
+{
+#ifdef HAVE_MITSHM
+  if (shminfo) {
+    vlog.debug("Freeing shared memory XImage");
+    shmdt(shminfo->shmaddr);
+    shmctl(shminfo->shmid, IPC_RMID, 0);
+    delete shminfo;
+    shminfo = 0;
+    imageCleanup.images.remove(this);
+  }
+#endif
+  // XDestroyImage() will free(xim->data) if appropriate
+  if (xim) XDestroyImage(xim);
+  xim = 0;
+}
+
+
+static bool supportedBPP(int bpp) {
+  return (bpp == 8 || bpp == 16 || bpp == 32);
+}
+
+static int depth2bpp(Display* dpy, int depth)
+{
+  int nformats;
+  XPixmapFormatValues* format = XListPixmapFormats(dpy, &nformats);
+
+  int i;
+  for (i = 0; i < nformats; i++)
+    if (format[i].depth == depth) break;
+
+  if (i == nformats || !supportedBPP(format[i].bits_per_pixel))
+    throw rfb::Exception("Error: couldn't find suitable pixmap format");
+
+  int bpp = format[i].bits_per_pixel;
+  XFree(format);
+  return bpp;
+}
+
+void TXImage::getNativePixelFormat(Visual* vis, int depth)
+{
+  cube = 0;
+  nativePF.depth = depth;
+  nativePF.bpp = depth2bpp(dpy, depth);
+  nativePF.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
+  nativePF.trueColour = (vis->c_class == TrueColor);
+
+  vlog.info("Using default colormap and visual, %sdepth %d.",
+            (vis->c_class == TrueColor) ? "TrueColor, " :
+            ((vis->c_class == PseudoColor) ? "PseudoColor, " : ""),
+            depth);
+
+  if (nativePF.trueColour) {
+
+    nativePF.redShift   = ffs(vis->red_mask)   - 1;
+    nativePF.greenShift = ffs(vis->green_mask) - 1;
+    nativePF.blueShift  = ffs(vis->blue_mask)  - 1;
+    nativePF.redMax   = vis->red_mask   >> nativePF.redShift;
+    nativePF.greenMax = vis->green_mask >> nativePF.greenShift;
+    nativePF.blueMax  = vis->blue_mask  >> nativePF.blueShift;
+
+  } else {
+
+    XColor xc[256];
+    cube = new rfb::ColourCube(6,6,6);
+    int r;
+    for (r = 0; r < cube->nRed; r++) {
+      for (int g = 0; g < cube->nGreen; g++) {
+        for (int b = 0; b < cube->nBlue; b++) {
+          int i = (r * cube->nGreen + g) * cube->nBlue + b;
+          xc[i].red =   r * 65535 / (cube->nRed-1);
+          xc[i].green = g * 65535 / (cube->nGreen-1);
+          xc[i].blue =  b * 65535 / (cube->nBlue-1);
+        }
+      }
+    }
+
+    TXWindow::getColours(dpy, xc, cube->size());
+
+    for (r = 0; r < cube->nRed; r++) {
+      for (int g = 0; g < cube->nGreen; g++) {
+        for (int b = 0; b < cube->nBlue; b++) {
+          int i = (r * cube->nGreen + g) * cube->nBlue + b;
+          cube->set(r, g, b, xc[i].pixel);
+        }
+      }
+    }
+  }
+}