00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "x11framebuffer.h"
00011 #include "x11framebuffer.moc"
00012
00013 #include <config-krfb.h>
00014
00015 #include <QX11Info>
00016 #include <QApplication>
00017 #include <QDesktopWidget>
00018
00019 #include <KApplication>
00020 #include <KDebug>
00021
00022 #include <X11/Xlib.h>
00023 #include <X11/Xutil.h>
00024
00025 #ifdef HAVE_XDAMAGE
00026 #include <X11/extensions/Xdamage.h>
00027 #endif
00028
00029 #ifdef HAVE_XSHM
00030 #include <sys/ipc.h>
00031 #include <sys/shm.h>
00032 #include <X11/extensions/XShm.h>
00033 #endif
00034
00035 class X11FrameBuffer::P {
00036
00037 public:
00038 #ifdef HAVE_XDAMAGE
00039 Damage damage;
00040 #endif
00041 #ifdef HAVE_XSHM
00042 XShmSegmentInfo shminfo;
00043 #endif
00044
00045 XImage *framebufferImage;
00046 XImage *updateTile;
00047 EvWidget *ev;
00048 bool useShm;
00049 int xdamageBaseEvent;
00050 bool running;
00051 };
00052
00053 X11FrameBuffer::X11FrameBuffer(WId id, QObject* parent)
00054 :FrameBuffer(id, parent), d(new X11FrameBuffer::P)
00055 {
00056 #ifdef HAVE_XSHM
00057 d->useShm = XShmQueryExtension(QX11Info::display());
00058 kDebug() << "shm: " << d->useShm;
00059 #else
00060 d->useShm = false;
00061 #endif
00062 d->running = false;
00063 d->framebufferImage = XGetImage(QX11Info::display(),
00064 id,
00065 0,
00066 0,
00067 QApplication::desktop()->width(),
00068 QApplication::desktop()->height(),
00069 AllPlanes,
00070 ZPixmap);
00071 if (d->useShm) {
00072 #ifdef HAVE_XSHM
00073 d->updateTile = XShmCreateImage(QX11Info::display(),
00074 DefaultVisual( QX11Info::display(), 0 ),
00075 d->framebufferImage->bits_per_pixel,
00076 ZPixmap,
00077 NULL,
00078 &d->shminfo,
00079 32,
00080 32);
00081 d->shminfo.shmid = shmget(IPC_PRIVATE,
00082 d->updateTile->bytes_per_line * d->updateTile->height,
00083 IPC_CREAT | 0777);
00084
00085 d->shminfo.shmaddr = d->updateTile->data = (char *)
00086 shmat(d->shminfo.shmid, 0, 0);
00087 d->shminfo.readOnly = False;
00088
00089 XShmAttach(QX11Info::display(), &d->shminfo);
00090 #endif
00091 } else {
00092 ;
00093 }
00094 kDebug() << "Got image. bpp: " << d->framebufferImage->bits_per_pixel
00095 << ", depth: " << d->framebufferImage->depth
00096 << ", padded width: " << d->framebufferImage->bytes_per_line
00097 << " (sent: " << d->framebufferImage->width * 4 << ")"
00098 << endl;
00099
00100 fb = d->framebufferImage->data;
00101 #ifdef HAVE_XDAMAGE
00102 d->ev = new EvWidget(this);
00103 kapp->installX11EventFilter(d->ev);
00104 #endif
00105 }
00106
00107
00108 X11FrameBuffer::~X11FrameBuffer()
00109 {
00110 XDestroyImage(d->framebufferImage);
00111 #ifdef HAVE_XDAMAGE
00112 kapp->removeX11EventFilter(d->ev);
00113 #endif
00114 #ifdef HAVE_XSHM
00115 XShmDetach(QX11Info::display(), &d->shminfo);
00116 XDestroyImage(d->updateTile);
00117 shmdt(d->shminfo.shmaddr);
00118 shmctl(d->shminfo.shmid, IPC_RMID, 0);
00119 #endif
00120 delete d;
00121 fb = 0;
00122 }
00123
00124
00125 int X11FrameBuffer::depth()
00126 {
00127 return d->framebufferImage->depth;
00128 }
00129
00130 int X11FrameBuffer::height()
00131 {
00132 return d->framebufferImage->height;
00133 }
00134
00135 int X11FrameBuffer::width()
00136 {
00137 return d->framebufferImage->width;
00138 }
00139
00140 int X11FrameBuffer::paddedWidth()
00141 {
00142 return d->framebufferImage->bytes_per_line;
00143 }
00144
00145 void X11FrameBuffer::getServerFormat(rfbPixelFormat& format)
00146 {
00147 format.bitsPerPixel = d->framebufferImage->bits_per_pixel;
00148 format.depth = d->framebufferImage->depth;
00149 format.trueColour = true;
00150 format.bigEndian = ((d->framebufferImage->bitmap_bit_order == MSBFirst) ? true : false);
00151
00152 if ( format.bitsPerPixel == 8 ) {
00153 format.redShift = 0;
00154 format.greenShift = 3;
00155 format.blueShift = 6;
00156 format.redMax = 7;
00157 format.greenMax = 7;
00158 format.blueMax = 3;
00159 } else {
00160 format.redShift = 0;
00161 if ( d->framebufferImage->red_mask )
00162 while ( ! ( d->framebufferImage->red_mask & (1 << format.redShift) ) )
00163 format.redShift++;
00164 format.greenShift = 0;
00165 if ( d->framebufferImage->green_mask )
00166 while ( ! ( d->framebufferImage->green_mask & (1 << format.greenShift) ) )
00167 format.greenShift++;
00168 format.blueShift = 0;
00169 if ( d->framebufferImage->blue_mask )
00170 while ( ! ( d->framebufferImage->blue_mask & (1 << format.blueShift) ) )
00171 format.blueShift++;
00172 format.redMax = d->framebufferImage->red_mask >> format.redShift;
00173 format.greenMax = d->framebufferImage->green_mask >> format.greenShift;
00174 format.blueMax = d->framebufferImage->blue_mask >> format.blueShift;
00175 }
00176 }
00177
00178 void X11FrameBuffer::handleXDamage(XEvent * event)
00179 {
00180 #ifdef HAVE_XDAMAGE
00181 XDamageNotifyEvent *dev = (XDamageNotifyEvent *)event;
00182 QRect r(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
00183 tiles.append(r);
00184
00185
00186
00187
00188 #endif
00189 }
00190
00191
00192 void X11FrameBuffer::cleanupRects() {
00193
00194 QList<QRect> cpy = tiles;
00195 bool inserted = false;
00196 tiles.clear();
00197
00198 foreach (const QRect &r, cpy) {
00199 if (tiles.size() > 0) {
00200 for(int i = 0; i < tiles.size(); i++) {
00201
00202 if (r.intersects(tiles[i])) {
00203 tiles[i] |= r;
00204 inserted = true;
00205 break;
00206
00207 }
00208 }
00209 if (!inserted) {
00210 tiles.append(r);
00211
00212 }
00213 } else {
00214
00215 tiles.append(r);
00216 }
00217 }
00218 for(int i = 0; i < tiles.size(); i++) {
00219 tiles[i].adjust(-30,-30,30,30);
00220 if (tiles[i].top() < 0){
00221 tiles[i].setTop(0);
00222 }
00223 if (tiles[i].left() < 0){
00224 tiles[i].setLeft(0);
00225 }
00226 if (tiles[i].bottom() > d->framebufferImage->height) {
00227 tiles[i].setBottom(d->framebufferImage->height);
00228 }
00229 if (tiles[i].right() > d->framebufferImage->width) {
00230 tiles[i].setRight(d->framebufferImage->width);
00231 }
00232 }
00233
00234 }
00235
00236 void X11FrameBuffer::acquireEvents() {
00237
00238 XEvent ev;
00239 while (XCheckTypedEvent(QX11Info::display(), d->xdamageBaseEvent+XDamageNotify, &ev)) {
00240 handleXDamage(&ev);
00241 }
00242 XDamageSubtract(QX11Info::display(),d->damage, None, None);
00243 }
00244
00245 QList< QRect > X11FrameBuffer::modifiedTiles()
00246 {
00247 QList<QRect> ret;
00248 if (!d->running) return ret;
00249 kapp->processEvents();
00250 cleanupRects();
00251 QRect gl;
00252
00253 if (tiles.size() > 0) {
00254 if (d->useShm) {
00255 #ifdef HAVE_XSHM
00256
00257 foreach(const QRect &r, tiles) {
00258
00259 gl |= r;
00260 int y = r.y();
00261 int x = r.x();
00262 while (x < r.right() ) {
00263 while (y < r.bottom() ) {
00264 if (y+d->updateTile->height > d->framebufferImage->height) {
00265 y = d->framebufferImage->height - d->updateTile->height;
00266 }
00267 if (x+d->updateTile->width > d->framebufferImage->width) {
00268 x = d->framebufferImage->width - d->updateTile->width;
00269 }
00270
00271 XShmGetImage(QX11Info::display(), win, d->updateTile, x, y, AllPlanes);
00272 int pxsize = d->framebufferImage->bits_per_pixel / 8;
00273 char *dest = fb + ((d->framebufferImage->bytes_per_line * y) + (x*pxsize));
00274 char *src = d->updateTile->data;
00275 for (int i = 0; i < d->updateTile->height; i++) {
00276 memcpy(dest, src, d->updateTile->bytes_per_line);
00277 dest += d->framebufferImage->bytes_per_line;
00278 src += d->updateTile->bytes_per_line;
00279 }
00280 y += d->updateTile->height;
00281 }
00282 x += d->updateTile->width;
00283 y = r.y();
00284 }
00285 }
00286 #endif
00287 } else {
00288 foreach(const QRect &r, tiles) {
00289 XGetSubImage(QX11Info::display(),
00290 win,
00291 r.left(),
00292 r.top(),
00293 r.width(),
00294 r.height(),
00295 AllPlanes,
00296 ZPixmap,
00297 d->framebufferImage,
00298 r.left(),
00299 r.top()
00300 );
00301 }
00302 }
00303 }
00304
00305
00306 ret = tiles;
00307 tiles.clear();
00308 return ret;
00309 }
00310
00311 void X11FrameBuffer::startMonitor()
00312 {
00313 d->running = true;
00314 #ifdef HAVE_XDAMAGE
00315 d->damage = XDamageCreate(QX11Info::display(), win, XDamageReportRawRectangles);
00316 XDamageSubtract(QX11Info::display(),d->damage, None, None);
00317 #endif
00318 }
00319
00320 void X11FrameBuffer::stopMonitor()
00321 {
00322 d->running = false;
00323 #ifdef HAVE_XDAMAGE
00324 XDamageDestroy(QX11Info::display(),d->damage);
00325 #endif
00326 }
00327
00328
00329
00330 EvWidget::EvWidget(X11FrameBuffer * x11fb)
00331 :QWidget(0), fb(x11fb)
00332 {
00333 #ifdef HAVE_XDAMAGE
00334 int er;
00335 XDamageQueryExtension(QX11Info::display(), &xdamageBaseEvent, &er);
00336 #endif
00337 }
00338
00339 bool EvWidget::x11Event(XEvent * event)
00340 {
00341 #ifdef HAVE_XDAMAGE
00342 if (event->type == xdamageBaseEvent+XDamageNotify) {
00343 fb->handleXDamage(event);
00344 return true;
00345 }
00346 #endif
00347 return false;
00348 }
00349
00350
00351