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.

X11PixelBuffer.cxx 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2011-2014 Pierre Ossman for Cendio AB
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include <config.h>
  21. #endif
  22. #include <assert.h>
  23. #include <stdlib.h>
  24. #include <FL/x.H>
  25. #include <rfb/LogWriter.h>
  26. #include <rfb/Exception.h>
  27. #include "X11PixelBuffer.h"
  28. using namespace rfb;
  29. static rfb::LogWriter vlog("X11PixelBuffer");
  30. static PixelFormat display_pf()
  31. {
  32. int i;
  33. int bpp;
  34. int trueColour, bigEndian;
  35. int redShift, greenShift, blueShift;
  36. int redMax, greenMax, blueMax;
  37. int nformats;
  38. XPixmapFormatValues* format;
  39. // Might not be open at this point
  40. fl_open_display();
  41. format = XListPixmapFormats(fl_display, &nformats);
  42. for (i = 0; i < nformats; i++)
  43. if (format[i].depth == fl_visual->depth) break;
  44. if (i == nformats)
  45. throw rfb::Exception("Error: display lacks pixmap format for default depth");
  46. switch (format[i].bits_per_pixel) {
  47. case 8:
  48. case 16:
  49. case 32:
  50. bpp = format[i].bits_per_pixel;
  51. break;
  52. default:
  53. throw rfb::Exception("Error: couldn't find suitable pixmap format");
  54. }
  55. XFree(format);
  56. bigEndian = (ImageByteOrder(fl_display) == MSBFirst);
  57. trueColour = (fl_visual->c_class == TrueColor);
  58. if (!trueColour)
  59. throw rfb::Exception("Error: only true colour displays supported");
  60. vlog.info("Using default colormap and visual, %sdepth %d.",
  61. (fl_visual->c_class == TrueColor) ? "TrueColor, " :
  62. ((fl_visual->c_class == PseudoColor) ? "PseudoColor, " : ""),
  63. fl_visual->depth);
  64. redShift = ffs(fl_visual->red_mask) - 1;
  65. greenShift = ffs(fl_visual->green_mask) - 1;
  66. blueShift = ffs(fl_visual->blue_mask) - 1;
  67. redMax = fl_visual->red_mask >> redShift;
  68. greenMax = fl_visual->green_mask >> greenShift;
  69. blueMax = fl_visual->blue_mask >> blueShift;
  70. return PixelFormat(bpp, fl_visual->depth, bigEndian, trueColour,
  71. redMax, greenMax, blueMax,
  72. redShift, greenShift, blueShift);
  73. }
  74. X11PixelBuffer::X11PixelBuffer(int width, int height) :
  75. PlatformPixelBuffer(display_pf(), width, height, NULL, 0),
  76. shminfo(NULL), xim(NULL)
  77. {
  78. // Might not be open at this point
  79. fl_open_display();
  80. if (!setupShm()) {
  81. xim = XCreateImage(fl_display, fl_visual->visual, fl_visual->depth,
  82. ZPixmap, 0, 0, width, height, BitmapPad(fl_display), 0);
  83. assert(xim);
  84. xim->data = (char*)malloc(xim->bytes_per_line * xim->height);
  85. assert(xim->data);
  86. }
  87. data = (rdr::U8*)xim->data;
  88. stride = xim->bytes_per_line / (getPF().bpp/8);
  89. }
  90. X11PixelBuffer::~X11PixelBuffer()
  91. {
  92. if (shminfo) {
  93. vlog.debug("Freeing shared memory XImage");
  94. shmdt(shminfo->shmaddr);
  95. shmctl(shminfo->shmid, IPC_RMID, 0);
  96. delete shminfo;
  97. shminfo = NULL;
  98. }
  99. // XDestroyImage() will free(xim->data) if appropriate
  100. if (xim)
  101. XDestroyImage(xim);
  102. xim = NULL;
  103. }
  104. void X11PixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h)
  105. {
  106. if (shminfo)
  107. XShmPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h, False);
  108. else
  109. XPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h);
  110. }
  111. static bool caughtError;
  112. static int XShmAttachErrorHandler(Display *dpy, XErrorEvent *error)
  113. {
  114. caughtError = true;
  115. return 0;
  116. }
  117. int X11PixelBuffer::setupShm()
  118. {
  119. int major, minor;
  120. Bool pixmaps;
  121. XErrorHandler old_handler;
  122. Status status;
  123. if (!XShmQueryVersion(fl_display, &major, &minor, &pixmaps))
  124. return 0;
  125. shminfo = new XShmSegmentInfo;
  126. xim = XShmCreateImage(fl_display, fl_visual->visual, fl_visual->depth,
  127. ZPixmap, 0, shminfo, width(), height());
  128. if (!xim)
  129. goto free_shminfo;
  130. shminfo->shmid = shmget(IPC_PRIVATE,
  131. xim->bytes_per_line * xim->height,
  132. IPC_CREAT|0777);
  133. if (shminfo->shmid == -1)
  134. goto free_xim;
  135. shminfo->shmaddr = xim->data = (char*)shmat(shminfo->shmid, 0, 0);
  136. if (shminfo->shmaddr == (char *)-1)
  137. goto free_shm;
  138. shminfo->readOnly = True;
  139. // This is the only way we can detect that shared memory won't work
  140. // (e.g. because we're accessing a remote X11 server)
  141. caughtError = false;
  142. old_handler = XSetErrorHandler(XShmAttachErrorHandler);
  143. XShmAttach(fl_display, shminfo);
  144. XSync(fl_display, False);
  145. XSetErrorHandler(old_handler);
  146. if (caughtError)
  147. goto free_shmaddr;
  148. vlog.debug("Using shared memory XImage");
  149. return 1;
  150. free_shmaddr:
  151. shmdt(shminfo->shmaddr);
  152. free_shm:
  153. shmctl(shminfo->shmid, IPC_RMID, 0);
  154. free_xim:
  155. XDestroyImage(xim);
  156. xim = NULL;
  157. free_shminfo:
  158. delete shminfo;
  159. shminfo = NULL;
  160. return 0;
  161. }