aboutsummaryrefslogtreecommitdiffstats
path: root/vncviewer/PlatformPixelBuffer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vncviewer/PlatformPixelBuffer.cxx')
-rw-r--r--vncviewer/PlatformPixelBuffer.cxx166
1 files changed, 161 insertions, 5 deletions
diff --git a/vncviewer/PlatformPixelBuffer.cxx b/vncviewer/PlatformPixelBuffer.cxx
index 522bad3f..4802ba46 100644
--- a/vncviewer/PlatformPixelBuffer.cxx
+++ b/vncviewer/PlatformPixelBuffer.cxx
@@ -1,4 +1,4 @@
-/* Copyright 2011-2014 Pierre Ossman for Cendio AB
+/* Copyright 2011-2016 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,13 +16,70 @@
* USA.
*/
+#include <assert.h>
+
+#if !defined(WIN32) && !defined(__APPLE__)
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif
+
+#include <FL/Fl.H>
+#include <FL/x.H>
+
+#include <rfb/LogWriter.h>
+#include <rdr/Exception.h>
+
#include "PlatformPixelBuffer.h"
-PlatformPixelBuffer::PlatformPixelBuffer(const rfb::PixelFormat& pf,
- int width, int height,
- rdr::U8* data, int stride) :
- FullFramePixelBuffer(pf, width, height, data, stride)
+static rfb::LogWriter vlog("PlatformPixelBuffer");
+
+PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) :
+ FullFramePixelBuffer(rfb::PixelFormat(32, 24, false, true,
+ 255, 255, 255, 16, 8, 0),
+ width, height, 0, stride),
+ Surface(width, height)
+#if !defined(WIN32) && !defined(__APPLE__)
+ , shminfo(NULL), xim(NULL)
+#endif
{
+#if !defined(WIN32) && !defined(__APPLE__)
+ if (!setupShm()) {
+ xim = XCreateImage(fl_display, CopyFromParent, 32,
+ ZPixmap, 0, 0, width, height, 32, 0);
+ if (!xim)
+ throw rdr::Exception("XCreateImage");
+
+ xim->data = (char*)malloc(xim->bytes_per_line * xim->height);
+ if (!xim->data)
+ throw rdr::Exception("malloc");
+
+ vlog.debug("Using standard XImage");
+ }
+
+ data = (rdr::U8*)xim->data;
+ stride = xim->bytes_per_line / (getPF().bpp/8);
+#else
+ FullFramePixelBuffer::data = (rdr::U8*)Surface::data;
+ stride = width;
+#endif
+}
+
+PlatformPixelBuffer::~PlatformPixelBuffer()
+{
+#if !defined(WIN32) && !defined(__APPLE__)
+ if (shminfo) {
+ vlog.debug("Freeing shared memory XImage");
+ shmdt(shminfo->shmaddr);
+ shmctl(shminfo->shmid, IPC_RMID, 0);
+ delete shminfo;
+ shminfo = NULL;
+ }
+
+ // XDestroyImage() will free(xim->data) if appropriate
+ if (xim)
+ XDestroyImage(xim);
+ xim = NULL;
+#endif
}
void PlatformPixelBuffer::commitBufferRW(const rfb::Rect& r)
@@ -42,5 +99,104 @@ rfb::Rect PlatformPixelBuffer::getDamage(void)
damage.clear();
mutex.unlock();
+#if !defined(WIN32) && !defined(__APPLE__)
+ GC gc;
+
+ gc = XCreateGC(fl_display, pixmap, 0, NULL);
+ if (shminfo) {
+ XShmPutImage(fl_display, pixmap, gc, xim,
+ r.tl.x, r.tl.y, r.tl.x, r.tl.y,
+ r.width(), r.height(), False);
+ // Need to make sure the X server has finished reading the
+ // shared memory before we return
+ XSync(fl_display, False);
+ } else {
+ XPutImage(fl_display, pixmap, gc, xim,
+ r.tl.x, r.tl.y, r.tl.x, r.tl.y, r.width(), r.height());
+ }
+ XFreeGC(fl_display, gc);
+#endif
+
return r;
}
+
+#if !defined(WIN32) && !defined(__APPLE__)
+
+static bool caughtError;
+
+static int XShmAttachErrorHandler(Display *dpy, XErrorEvent *error)
+{
+ caughtError = true;
+ return 0;
+}
+
+bool PlatformPixelBuffer::setupShm()
+{
+ int major, minor;
+ Bool pixmaps;
+ XErrorHandler old_handler;
+ const char *display_name = XDisplayName (NULL);
+
+ /* Don't use MIT-SHM on remote displays */
+ if (*display_name && *display_name != ':')
+ return false;
+
+ if (!XShmQueryVersion(fl_display, &major, &minor, &pixmaps))
+ return false;
+
+ shminfo = new XShmSegmentInfo;
+
+ xim = XShmCreateImage(fl_display, CopyFromParent, 32,
+ ZPixmap, 0, shminfo, width(), height());
+ if (!xim)
+ goto free_shminfo;
+
+ shminfo->shmid = shmget(IPC_PRIVATE,
+ xim->bytes_per_line * xim->height,
+ IPC_CREAT|0777);
+ if (shminfo->shmid == -1)
+ goto free_xim;
+
+ shminfo->shmaddr = xim->data = (char*)shmat(shminfo->shmid, 0, 0);
+ shmctl(shminfo->shmid, IPC_RMID, 0); // to avoid memory leakage
+ if (shminfo->shmaddr == (char *)-1)
+ goto free_xim;
+
+ shminfo->readOnly = True;
+
+ // This is the only way we can detect that shared memory won't work
+ // (e.g. because we're accessing a remote X11 server)
+ caughtError = false;
+ old_handler = XSetErrorHandler(XShmAttachErrorHandler);
+
+ if (!XShmAttach(fl_display, shminfo)) {
+ XSetErrorHandler(old_handler);
+ goto free_shmaddr;
+ }
+
+ XSync(fl_display, False);
+
+ XSetErrorHandler(old_handler);
+
+ if (caughtError)
+ goto free_shmaddr;
+
+ vlog.debug("Using shared memory XImage");
+
+ return true;
+
+free_shmaddr:
+ shmdt(shminfo->shmaddr);
+
+free_xim:
+ XDestroyImage(xim);
+ xim = NULL;
+
+free_shminfo:
+ delete shminfo;
+ shminfo = NULL;
+
+ return 0;
+}
+
+#endif