--- /dev/null
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011 Pierre Ossman <ossman@cendio.se> 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
+ * 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.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <FL/x.H>
+
+#include <rfb/LogWriter.h>
+#include <rfb/Exception.h>
+
+#include "X11PixelBuffer.h"
+
+using namespace rfb;
+
+static rfb::LogWriter vlog("PlatformPixelBuffer");
+
+static PixelFormat display_pf()
+{
+ int i;
+
+ int bpp;
+ int trueColour, bigEndian;
+ int redShift, greenShift, blueShift;
+ int redMax, greenMax, blueMax;
+
+ int nformats;
+ XPixmapFormatValues* format;
+
+ // Might not be open at this point
+ fl_open_display();
+
+ format = XListPixmapFormats(fl_display, &nformats);
+
+ for (i = 0; i < nformats; i++)
+ if (format[i].depth == fl_visual->depth) break;
+
+ if (i == nformats)
+ throw rfb::Exception("Error: display lacks pixmap format for default depth");
+
+ switch (format[i].bits_per_pixel) {
+ case 8:
+ case 16:
+ case 32:
+ bpp = format[i].bits_per_pixel;
+ break;
+ default:
+ throw rfb::Exception("Error: couldn't find suitable pixmap format");
+ }
+
+ XFree(format);
+
+ bigEndian = (ImageByteOrder(fl_display) == MSBFirst);
+ trueColour = (fl_visual->c_class == TrueColor);
+
+ if (!trueColour)
+ throw rfb::Exception("Error: only true colour displays supported");
+
+ vlog.info("Using default colormap and visual, %sdepth %d.",
+ (fl_visual->c_class == TrueColor) ? "TrueColor, " :
+ ((fl_visual->c_class == PseudoColor) ? "PseudoColor, " : ""),
+ fl_visual->depth);
+
+ redShift = ffs(fl_visual->red_mask) - 1;
+ greenShift = ffs(fl_visual->green_mask) - 1;
+ blueShift = ffs(fl_visual->blue_mask) - 1;
+ redMax = fl_visual->red_mask >> redShift;
+ greenMax = fl_visual->green_mask >> greenShift;
+ blueMax = fl_visual->blue_mask >> blueShift;
+
+ return PixelFormat(bpp, fl_visual->depth, bigEndian, trueColour,
+ redMax, greenMax, blueMax,
+ redShift, greenShift, blueShift);
+}
+
+PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) :
+ FullFramePixelBuffer(display_pf(), width, height, NULL, NULL),
+ shminfo(NULL), xim(NULL)
+{
+ // Might not be open at this point
+ fl_open_display();
+
+ if (!setupShm()) {
+ xim = XCreateImage(fl_display, fl_visual->visual, fl_visual->depth,
+ ZPixmap, 0, 0, width, height, BitmapPad(fl_display), 0);
+ assert(xim);
+
+ xim->data = (char*)malloc(xim->bytes_per_line * xim->height);
+ assert(xim->data);
+ }
+
+ data = (rdr::U8*)xim->data;
+}
+
+
+PlatformPixelBuffer::~PlatformPixelBuffer()
+{
+ 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;
+}
+
+
+void PlatformPixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h)
+{
+ if (shminfo)
+ XShmPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h, False);
+ else
+ XPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h);
+}
+
+
+int PlatformPixelBuffer::getStride() const
+{
+ return xim->bytes_per_line / (getPF().bpp/8);
+}
+
+
+int PlatformPixelBuffer::setupShm()
+{
+ int major, minor;
+ Bool pixmaps;
+
+ if (!XShmQueryVersion(fl_display, &major, &minor, &pixmaps))
+ return 0;
+
+ shminfo = new XShmSegmentInfo;
+
+ xim = XShmCreateImage(fl_display, fl_visual->visual, fl_visual->depth,
+ 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);
+ if (shminfo->shmaddr == (char *)-1)
+ goto free_shm;
+
+ shminfo->readOnly = True;
+ XShmAttach(fl_display, shminfo);
+
+ vlog.debug("Using shared memory XImage");
+
+ return 1;
+
+free_shm:
+ shmctl(shminfo->shmid, IPC_RMID, 0);
+
+free_xim:
+ XDestroyImage(xim);
+ xim = NULL;
+
+free_shminfo:
+ delete shminfo;
+ shminfo = NULL;
+
+ return 0;
+}
--- /dev/null
+/* Copyright 2011 Pierre Ossman <ossman@cendio.se> 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
+ * 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.
+ */
+
+#ifndef __X11PIXELBUFFER_H__
+#define __X11PIXELBUFFER_H__
+
+#include <X11/Xlib.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+
+#include <rfb/PixelBuffer.h>
+
+class PlatformPixelBuffer: public rfb::FullFramePixelBuffer {
+public:
+ PlatformPixelBuffer(int width, int height);
+ ~PlatformPixelBuffer();
+
+ void draw(int src_x, int src_y, int x, int y, int w, int h);
+
+ int getStride() const;
+
+protected:
+ int setupShm();
+
+protected:
+ XShmSegmentInfo *shminfo;
+ XImage *xim;
+};
+
+
+#endif