* do not add a KStandardAction manually to actionCollection()
[kdenetwork.git] / krfb / x11framebuffer.cpp
blob96419815bd86aae12d854fc5881f69cfb444448a
1 /* This file is part of the KDE project
2 Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8 */
10 #include "x11framebuffer.h"
11 #include "x11framebuffer.moc"
13 #include <config-krfb.h>
15 #include <QX11Info>
16 #include <QApplication>
17 #include <QDesktopWidget>
19 #include <KApplication>
20 #include <KDebug>
22 #include <X11/Xlib.h>
23 #include <X11/Xutil.h>
25 #ifdef HAVE_XDAMAGE
26 #include <X11/extensions/Xdamage.h>
27 #endif
29 #ifdef HAVE_XSHM
30 #include <sys/ipc.h>
31 #include <sys/shm.h>
32 #include <X11/extensions/XShm.h>
33 #endif
35 class X11FrameBuffer::P {
37 public:
38 #ifdef HAVE_XDAMAGE
39 Damage damage;
40 #endif
41 #ifdef HAVE_XSHM
42 XShmSegmentInfo shminfo;
43 #endif
45 XImage *framebufferImage;
46 XImage *updateTile;
47 EvWidget *ev;
48 bool useShm;
49 int xdamageBaseEvent;
50 bool running;
53 X11FrameBuffer::X11FrameBuffer(WId id, QObject* parent)
54 :FrameBuffer(id, parent), d(new X11FrameBuffer::P)
56 #ifdef HAVE_XSHM
57 d->useShm = XShmQueryExtension(QX11Info::display());
58 kDebug() << "shm: " << d->useShm;
59 #else
60 d->useShm = false;
61 #endif
62 d->running = false;
63 d->framebufferImage = XGetImage(QX11Info::display(),
64 id,
67 QApplication::desktop()->width(), //arg, must get a widget ???
68 QApplication::desktop()->height(),
69 AllPlanes,
70 ZPixmap);
71 if (d->useShm) {
72 #ifdef HAVE_XSHM
73 d->updateTile = XShmCreateImage(QX11Info::display(),
74 DefaultVisual( QX11Info::display(), 0 ),
75 d->framebufferImage->bits_per_pixel,
76 ZPixmap,
77 NULL,
78 &d->shminfo,
79 32,
80 32);
81 d->shminfo.shmid = shmget(IPC_PRIVATE,
82 d->updateTile->bytes_per_line * d->updateTile->height,
83 IPC_CREAT | 0777);
85 d->shminfo.shmaddr = d->updateTile->data = (char *)
86 shmat(d->shminfo.shmid, 0, 0);
87 d->shminfo.readOnly = False;
89 XShmAttach(QX11Info::display(), &d->shminfo);
90 #endif
91 } else {
94 kDebug() << "Got image. bpp: " << d->framebufferImage->bits_per_pixel
95 << ", depth: " << d->framebufferImage->depth
96 << ", padded width: " << d->framebufferImage->bytes_per_line
97 << " (sent: " << d->framebufferImage->width * 4 << ")"
98 << endl;
100 fb = d->framebufferImage->data;
101 #ifdef HAVE_XDAMAGE
102 d->ev = new EvWidget(this);
103 kapp->installX11EventFilter(d->ev);
104 #endif
108 X11FrameBuffer::~X11FrameBuffer()
110 XDestroyImage(d->framebufferImage);
111 #ifdef HAVE_XDAMAGE
112 kapp->removeX11EventFilter(d->ev);
113 #endif
114 #ifdef HAVE_XSHM
115 XShmDetach(QX11Info::display(), &d->shminfo);
116 XDestroyImage(d->updateTile);
117 shmdt(d->shminfo.shmaddr);
118 shmctl(d->shminfo.shmid, IPC_RMID, 0);
119 #endif
120 delete d;
121 fb = 0; // already deleted by XDestroyImage
125 int X11FrameBuffer::depth()
127 return d->framebufferImage->depth;
130 int X11FrameBuffer::height()
132 return d->framebufferImage->height;
135 int X11FrameBuffer::width()
137 return d->framebufferImage->width;
140 int X11FrameBuffer::paddedWidth()
142 return d->framebufferImage->bytes_per_line;
145 void X11FrameBuffer::getServerFormat(rfbPixelFormat& format)
147 format.bitsPerPixel = d->framebufferImage->bits_per_pixel;
148 format.depth = d->framebufferImage->depth;
149 format.trueColour = true;
150 format.bigEndian = ((d->framebufferImage->bitmap_bit_order == MSBFirst) ? true : false);
152 if ( format.bitsPerPixel == 8 ) {
153 format.redShift = 0;
154 format.greenShift = 3;
155 format.blueShift = 6;
156 format.redMax = 7;
157 format.greenMax = 7;
158 format.blueMax = 3;
159 } else {
160 format.redShift = 0;
161 if ( d->framebufferImage->red_mask )
162 while ( ! ( d->framebufferImage->red_mask & (1 << format.redShift) ) )
163 format.redShift++;
164 format.greenShift = 0;
165 if ( d->framebufferImage->green_mask )
166 while ( ! ( d->framebufferImage->green_mask & (1 << format.greenShift) ) )
167 format.greenShift++;
168 format.blueShift = 0;
169 if ( d->framebufferImage->blue_mask )
170 while ( ! ( d->framebufferImage->blue_mask & (1 << format.blueShift) ) )
171 format.blueShift++;
172 format.redMax = d->framebufferImage->red_mask >> format.redShift;
173 format.greenMax = d->framebufferImage->green_mask >> format.greenShift;
174 format.blueMax = d->framebufferImage->blue_mask >> format.blueShift;
178 void X11FrameBuffer::handleXDamage(XEvent * event)
180 #ifdef HAVE_XDAMAGE
181 XDamageNotifyEvent *dev = (XDamageNotifyEvent *)event;
182 QRect r(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
183 tiles.append(r);
185 /*if (!dev->more) {
186 XDamageSubtract(QX11Info::display(),d->damage, None, None);
188 #endif
192 void X11FrameBuffer::cleanupRects() {
194 QList<QRect> cpy = tiles;
195 bool inserted = false;
196 tiles.clear();
197 // kDebug() << "before cleanup: " << cpy.size();
198 foreach (const QRect &r, cpy) {
199 if (tiles.size() > 0) {
200 for(int i = 0; i < tiles.size(); i++) {
201 // kDebug() << r << tiles[i];
202 if (r.intersects(tiles[i])) {
203 tiles[i] |= r;
204 inserted = true;
205 break;
206 // kDebug() << "merged into " << tiles[i];
209 if (!inserted) {
210 tiles.append(r);
211 // kDebug() << "appended " << r;
213 } else {
214 // kDebug() << "appended " << r;
215 tiles.append(r);
218 for(int i = 0; i < tiles.size(); i++) {
219 tiles[i].adjust(-30,-30,30,30);
220 if (tiles[i].top() < 0){
221 tiles[i].setTop(0);
223 if (tiles[i].left() < 0){
224 tiles[i].setLeft(0);
226 if (tiles[i].bottom() > d->framebufferImage->height) {
227 tiles[i].setBottom(d->framebufferImage->height);
229 if (tiles[i].right() > d->framebufferImage->width) {
230 tiles[i].setRight(d->framebufferImage->width);
233 // kDebug() << "after cleanup: " << tiles.size();
236 void X11FrameBuffer::acquireEvents() {
238 XEvent ev;
239 while (XCheckTypedEvent(QX11Info::display(), d->xdamageBaseEvent+XDamageNotify, &ev)) {
240 handleXDamage(&ev);
242 XDamageSubtract(QX11Info::display(),d->damage, None, None);
245 QList< QRect > X11FrameBuffer::modifiedTiles()
247 QList<QRect> ret;
248 if (!d->running) return ret;
249 kapp->processEvents(); // try to make sure every damage event goes trough;
250 cleanupRects();
251 QRect gl;
252 //d->useShm = false;
253 if (tiles.size() > 0) {
254 if (d->useShm) {
255 #ifdef HAVE_XSHM
257 foreach(const QRect &r, tiles) {
258 // kDebug() << r;
259 gl |= r;
260 int y = r.y();
261 int x = r.x();
262 while (x < r.right() ) {
263 while (y < r.bottom() ) {
264 if (y+d->updateTile->height > d->framebufferImage->height) {
265 y = d->framebufferImage->height - d->updateTile->height;
267 if (x+d->updateTile->width > d->framebufferImage->width) {
268 x = d->framebufferImage->width - d->updateTile->width;
270 // kDebug() << "x: " << x << " (" << r.x() << ") y: " << y << " (" << r.y() << ") " << r;
271 XShmGetImage(QX11Info::display(), win, d->updateTile, x, y, AllPlanes);
272 int pxsize = d->framebufferImage->bits_per_pixel / 8;
273 char *dest = fb + ((d->framebufferImage->bytes_per_line * y) + (x*pxsize));
274 char *src = d->updateTile->data;
275 for (int i = 0; i < d->updateTile->height; i++) {
276 memcpy(dest, src, d->updateTile->bytes_per_line);
277 dest += d->framebufferImage->bytes_per_line;
278 src += d->updateTile->bytes_per_line;
280 y += d->updateTile->height;
282 x += d->updateTile->width;
283 y = r.y();
286 #endif
287 } else {
288 foreach(const QRect &r, tiles) {
289 XGetSubImage(QX11Info::display(),
290 win,
291 r.left(),
292 r.top(),
293 r.width(),
294 r.height(),
295 AllPlanes,
296 ZPixmap,
297 d->framebufferImage,
298 r.left(),
299 r.top()
304 // kDebug() << "tot: " << gl;
305 // kDebug() << tiles.size();
306 ret = tiles;
307 tiles.clear();
308 return ret;
311 void X11FrameBuffer::startMonitor()
313 d->running = true;
314 #ifdef HAVE_XDAMAGE
315 d->damage = XDamageCreate(QX11Info::display(), win, XDamageReportRawRectangles);
316 XDamageSubtract(QX11Info::display(),d->damage, None, None);
317 #endif
320 void X11FrameBuffer::stopMonitor()
322 d->running = false;
323 #ifdef HAVE_XDAMAGE
324 XDamageDestroy(QX11Info::display(),d->damage);
325 #endif
330 EvWidget::EvWidget(X11FrameBuffer * x11fb)
331 :QWidget(0), fb(x11fb)
333 #ifdef HAVE_XDAMAGE
334 int er;
335 XDamageQueryExtension(QX11Info::display(), &xdamageBaseEvent, &er);
336 #endif
339 bool EvWidget::x11Event(XEvent * event)
341 #ifdef HAVE_XDAMAGE
342 if (event->type == xdamageBaseEvent+XDamageNotify) {
343 fb->handleXDamage(event);
344 return true;
346 #endif
347 return false;