You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TXImage.cxx 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. //
  19. // TXImage.cxx
  20. //
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <strings.h>
  24. #include <sys/types.h>
  25. #include <sys/ipc.h>
  26. #include <sys/shm.h>
  27. #include <X11/Xlib.h>
  28. #include <X11/Xutil.h>
  29. #include <list>
  30. #include <rfb/TransImageGetter.h>
  31. #include <rfb/Exception.h>
  32. #include <rfb/LogWriter.h>
  33. #include "TXWindow.h"
  34. #include "TXImage.h"
  35. using namespace rfb;
  36. static rfb::LogWriter vlog("TXImage");
  37. TXImage::TXImage(Display* d, int width, int height, Visual* vis_, int depth_)
  38. : xim(0), dpy(d), vis(vis_), depth(depth_), tig(0), cube(0)
  39. {
  40. #ifdef HAVE_MITSHM
  41. shminfo = 0;
  42. #endif
  43. width_ = width;
  44. height_ = height;
  45. for (int i = 0; i < 256; i++)
  46. colourMap[i].r = colourMap[i].g = colourMap[i].b = 0;
  47. if (!vis)
  48. vis = DefaultVisual(dpy,DefaultScreen(dpy));
  49. if (!depth)
  50. depth = DefaultDepth(dpy,DefaultScreen(dpy));
  51. createXImage();
  52. getNativePixelFormat(vis, depth);
  53. colourmap = this;
  54. format.bpp = 0; // just make it different to any valid format, so that...
  55. setPF(nativePF); // ...setPF() always works
  56. }
  57. TXImage::~TXImage()
  58. {
  59. if (data != (rdr::U8*)xim->data) delete [] data;
  60. destroyXImage();
  61. delete tig;
  62. delete cube;
  63. }
  64. void TXImage::resize(int w, int h)
  65. {
  66. if (w == width() && h == height()) return;
  67. int oldStrideBytes = getStride() * (format.bpp/8);
  68. int rowsToCopy = __rfbmin(h, height());
  69. int bytesPerRow = __rfbmin(w, width()) * (format.bpp/8);
  70. rdr::U8* oldData = 0;
  71. bool allocData = false;
  72. if (data != (rdr::U8*)xim->data) {
  73. oldData = (rdr::U8*)data;
  74. allocData = true;
  75. } else {
  76. oldData = new rdr::U8[xim->bytes_per_line * height()];
  77. memcpy(oldData, xim->data, xim->bytes_per_line * height());
  78. }
  79. destroyXImage();
  80. width_ = w;
  81. height_ = h;
  82. createXImage();
  83. if (allocData)
  84. data = new rdr::U8[width() * height() * (format.bpp/8)];
  85. else
  86. data = (rdr::U8*)xim->data;
  87. int newStrideBytes = getStride() * (format.bpp/8);
  88. for (int i = 0; i < rowsToCopy; i++)
  89. memcpy((rdr::U8*)data + newStrideBytes * i, oldData + oldStrideBytes * i,
  90. bytesPerRow);
  91. delete [] oldData;
  92. }
  93. void TXImage::setPF(const PixelFormat& newPF)
  94. {
  95. if (newPF.equal(format)) return;
  96. format = newPF;
  97. if (data != (rdr::U8*)xim->data) delete [] data;
  98. delete tig;
  99. tig = 0;
  100. if (format.equal(nativePF) && format.trueColour) {
  101. data = (rdr::U8*)xim->data;
  102. } else {
  103. data = new rdr::U8[width() * height() * (format.bpp/8)];
  104. tig = new TransImageGetter();
  105. tig->init(this, nativePF, 0, cube);
  106. }
  107. }
  108. int TXImage::getStride() const
  109. {
  110. if (data == (rdr::U8*)xim->data)
  111. return xim->bytes_per_line / (xim->bits_per_pixel / 8);
  112. else
  113. return width();
  114. }
  115. void TXImage::put(Window win, GC gc, const rfb::Rect& r)
  116. {
  117. if (r.is_empty()) return;
  118. int x = r.tl.x;
  119. int y = r.tl.y;
  120. int w = r.width();
  121. int h = r.height();
  122. if (data != (rdr::U8*)xim->data) {
  123. rdr::U8* ximDataStart = ((rdr::U8*)xim->data + y * xim->bytes_per_line
  124. + x * (xim->bits_per_pixel / 8));
  125. tig->getImage(ximDataStart, r,
  126. xim->bytes_per_line / (xim->bits_per_pixel / 8));
  127. }
  128. #ifdef HAVE_MITSHM
  129. if (usingShm()) {
  130. XShmPutImage(dpy, win, gc, xim, x, y, x, y, w, h, False);
  131. return;
  132. }
  133. #endif
  134. XPutImage(dpy, win, gc, xim, x, y, x, y, w, h);
  135. }
  136. void TXImage::setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs)
  137. {
  138. for (int i = 0; i < nColours; i++) {
  139. colourMap[firstColour+i].r = rgbs[i*3];
  140. colourMap[firstColour+i].g = rgbs[i*3+1];
  141. colourMap[firstColour+i].b = rgbs[i*3+2];
  142. }
  143. }
  144. void TXImage::updateColourMap()
  145. {
  146. tig->setColourMapEntries(0, 0, 0);
  147. }
  148. void TXImage::lookup(int index, int* r, int* g, int* b)
  149. {
  150. *r = colourMap[index].r;
  151. *g = colourMap[index].g;
  152. *b = colourMap[index].b;
  153. }
  154. #ifdef HAVE_MITSHM
  155. static bool caughtError = false;
  156. static int XShmAttachErrorHandler(Display *dpy, XErrorEvent *error)
  157. {
  158. caughtError = true;
  159. return 0;
  160. }
  161. class TXImageCleanup {
  162. public:
  163. std::list<TXImage*> images;
  164. ~TXImageCleanup() {
  165. while (!images.empty())
  166. delete images.front();
  167. }
  168. };
  169. static TXImageCleanup imageCleanup;
  170. #endif
  171. void TXImage::createXImage()
  172. {
  173. #ifdef HAVE_MITSHM
  174. int major, minor;
  175. Bool pixmaps;
  176. if (XShmQueryVersion(dpy, &major, &minor, &pixmaps)) {
  177. shminfo = new XShmSegmentInfo;
  178. xim = XShmCreateImage(dpy, vis, depth, ZPixmap,
  179. 0, shminfo, width(), height());
  180. if (xim) {
  181. shminfo->shmid = shmget(IPC_PRIVATE,
  182. xim->bytes_per_line * xim->height,
  183. IPC_CREAT|0777);
  184. if (shminfo->shmid != -1) {
  185. shminfo->shmaddr = xim->data = (char*)shmat(shminfo->shmid, 0, 0);
  186. if (shminfo->shmaddr != (char *)-1) {
  187. shminfo->readOnly = False;
  188. XErrorHandler oldHdlr = XSetErrorHandler(XShmAttachErrorHandler);
  189. XShmAttach(dpy, shminfo);
  190. XSync(dpy, False);
  191. XSetErrorHandler(oldHdlr);
  192. if (!caughtError) {
  193. vlog.debug("Using shared memory XImage");
  194. imageCleanup.images.push_back(this);
  195. return;
  196. }
  197. shmdt(shminfo->shmaddr);
  198. } else {
  199. vlog.error("shmat failed");
  200. perror("shmat");
  201. }
  202. shmctl(shminfo->shmid, IPC_RMID, 0);
  203. } else {
  204. vlog.error("shmget failed");
  205. perror("shmget");
  206. }
  207. XDestroyImage(xim);
  208. xim = 0;
  209. } else {
  210. vlog.error("XShmCreateImage failed");
  211. }
  212. delete shminfo;
  213. shminfo = 0;
  214. }
  215. #endif
  216. xim = XCreateImage(dpy, vis, depth, ZPixmap,
  217. 0, 0, width(), height(), BitmapPad(dpy), 0);
  218. xim->data = (char*)malloc(xim->bytes_per_line * xim->height);
  219. if (!xim->data) {
  220. vlog.error("malloc failed");
  221. exit(1);
  222. }
  223. }
  224. void TXImage::destroyXImage()
  225. {
  226. #ifdef HAVE_MITSHM
  227. if (shminfo) {
  228. vlog.debug("Freeing shared memory XImage");
  229. shmdt(shminfo->shmaddr);
  230. shmctl(shminfo->shmid, IPC_RMID, 0);
  231. delete shminfo;
  232. shminfo = 0;
  233. imageCleanup.images.remove(this);
  234. }
  235. #endif
  236. // XDestroyImage() will free(xim->data) if appropriate
  237. if (xim) XDestroyImage(xim);
  238. xim = 0;
  239. }
  240. static bool supportedBPP(int bpp) {
  241. return (bpp == 8 || bpp == 16 || bpp == 32);
  242. }
  243. static int depth2bpp(Display* dpy, int depth)
  244. {
  245. int nformats;
  246. XPixmapFormatValues* format = XListPixmapFormats(dpy, &nformats);
  247. int i;
  248. for (i = 0; i < nformats; i++)
  249. if (format[i].depth == depth) break;
  250. if (i == nformats || !supportedBPP(format[i].bits_per_pixel))
  251. throw rfb::Exception("Error: couldn't find suitable pixmap format");
  252. int bpp = format[i].bits_per_pixel;
  253. XFree(format);
  254. return bpp;
  255. }
  256. void TXImage::getNativePixelFormat(Visual* vis, int depth)
  257. {
  258. cube = 0;
  259. nativePF.depth = depth;
  260. nativePF.bpp = depth2bpp(dpy, depth);
  261. nativePF.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
  262. nativePF.trueColour = (vis->c_class == TrueColor);
  263. vlog.info("Using default colormap and visual, %sdepth %d.",
  264. (vis->c_class == TrueColor) ? "TrueColor, " :
  265. ((vis->c_class == PseudoColor) ? "PseudoColor, " : ""),
  266. depth);
  267. if (nativePF.trueColour) {
  268. nativePF.redShift = ffs(vis->red_mask) - 1;
  269. nativePF.greenShift = ffs(vis->green_mask) - 1;
  270. nativePF.blueShift = ffs(vis->blue_mask) - 1;
  271. nativePF.redMax = vis->red_mask >> nativePF.redShift;
  272. nativePF.greenMax = vis->green_mask >> nativePF.greenShift;
  273. nativePF.blueMax = vis->blue_mask >> nativePF.blueShift;
  274. } else {
  275. XColor xc[256];
  276. cube = new rfb::ColourCube(6,6,6);
  277. int r;
  278. for (r = 0; r < cube->nRed; r++) {
  279. for (int g = 0; g < cube->nGreen; g++) {
  280. for (int b = 0; b < cube->nBlue; b++) {
  281. int i = (r * cube->nGreen + g) * cube->nBlue + b;
  282. xc[i].red = r * 65535 / (cube->nRed-1);
  283. xc[i].green = g * 65535 / (cube->nGreen-1);
  284. xc[i].blue = b * 65535 / (cube->nBlue-1);
  285. }
  286. }
  287. }
  288. TXWindow::getColours(dpy, xc, cube->size());
  289. for (r = 0; r < cube->nRed; r++) {
  290. for (int g = 0; g < cube->nGreen; g++) {
  291. for (int b = 0; b < cube->nBlue; b++) {
  292. int i = (r * cube->nGreen + g) * cube->nBlue + b;
  293. cube->set(r, g, b, xc[i].pixel);
  294. }
  295. }
  296. }
  297. }
  298. }