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.
10 #include "x11framebuffer.h"
11 #include "x11framebuffer.moc"
13 #include <config-krfb.h>
16 #include <QApplication>
17 #include <QDesktopWidget>
19 #include <KApplication>
23 #include <X11/Xutil.h>
26 #include <X11/extensions/Xdamage.h>
32 #include <X11/extensions/XShm.h>
35 class X11FrameBuffer::P
{
42 XShmSegmentInfo shminfo
;
45 XImage
*framebufferImage
;
53 X11FrameBuffer::X11FrameBuffer(WId id
, QObject
* parent
)
54 :FrameBuffer(id
, parent
), d(new X11FrameBuffer::P
)
57 d
->useShm
= XShmQueryExtension(QX11Info::display());
58 kDebug() << "shm: " << d
->useShm
;
63 d
->framebufferImage
= XGetImage(QX11Info::display(),
67 QApplication::desktop()->width(), //arg, must get a widget ???
68 QApplication::desktop()->height(),
73 d
->updateTile
= XShmCreateImage(QX11Info::display(),
74 DefaultVisual( QX11Info::display(), 0 ),
75 d
->framebufferImage
->bits_per_pixel
,
81 d
->shminfo
.shmid
= shmget(IPC_PRIVATE
,
82 d
->updateTile
->bytes_per_line
* d
->updateTile
->height
,
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
);
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 << ")"
100 fb
= d
->framebufferImage
->data
;
102 d
->ev
= new EvWidget(this);
103 kapp
->installX11EventFilter(d
->ev
);
108 X11FrameBuffer::~X11FrameBuffer()
110 XDestroyImage(d
->framebufferImage
);
112 kapp
->removeX11EventFilter(d
->ev
);
115 XShmDetach(QX11Info::display(), &d
->shminfo
);
116 XDestroyImage(d
->updateTile
);
117 shmdt(d
->shminfo
.shmaddr
);
118 shmctl(d
->shminfo
.shmid
, IPC_RMID
, 0);
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 ) {
154 format
.greenShift
= 3;
155 format
.blueShift
= 6;
161 if ( d
->framebufferImage
->red_mask
)
162 while ( ! ( d
->framebufferImage
->red_mask
& (1 << format
.redShift
) ) )
164 format
.greenShift
= 0;
165 if ( d
->framebufferImage
->green_mask
)
166 while ( ! ( d
->framebufferImage
->green_mask
& (1 << format
.greenShift
) ) )
168 format
.blueShift
= 0;
169 if ( d
->framebufferImage
->blue_mask
)
170 while ( ! ( d
->framebufferImage
->blue_mask
& (1 << 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
)
181 XDamageNotifyEvent
*dev
= (XDamageNotifyEvent
*)event
;
182 QRect
r(dev
->area
.x
, dev
->area
.y
, dev
->area
.width
, dev
->area
.height
);
186 XDamageSubtract(QX11Info::display(),d->damage, None, None);
192 void X11FrameBuffer::cleanupRects() {
194 QList
<QRect
> cpy
= tiles
;
195 bool inserted
= false;
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
])) {
206 // kDebug() << "merged into " << tiles[i];
211 // kDebug() << "appended " << r;
214 // kDebug() << "appended " << r;
218 for(int i
= 0; i
< tiles
.size(); i
++) {
219 tiles
[i
].adjust(-30,-30,30,30);
220 if (tiles
[i
].top() < 0){
223 if (tiles
[i
].left() < 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() {
239 while (XCheckTypedEvent(QX11Info::display(), d
->xdamageBaseEvent
+XDamageNotify
, &ev
)) {
242 XDamageSubtract(QX11Info::display(),d
->damage
, None
, None
);
245 QList
< QRect
> X11FrameBuffer::modifiedTiles()
248 if (!d
->running
) return ret
;
249 kapp
->processEvents(); // try to make sure every damage event goes trough;
253 if (tiles
.size() > 0) {
257 foreach(const QRect
&r
, tiles
) {
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
;
288 foreach(const QRect
&r
, tiles
) {
289 XGetSubImage(QX11Info::display(),
304 // kDebug() << "tot: " << gl;
305 // kDebug() << tiles.size();
311 void X11FrameBuffer::startMonitor()
315 d
->damage
= XDamageCreate(QX11Info::display(), win
, XDamageReportRawRectangles
);
316 XDamageSubtract(QX11Info::display(),d
->damage
, None
, None
);
320 void X11FrameBuffer::stopMonitor()
324 XDamageDestroy(QX11Info::display(),d
->damage
);
330 EvWidget::EvWidget(X11FrameBuffer
* x11fb
)
331 :QWidget(0), fb(x11fb
)
335 XDamageQueryExtension(QX11Info::display(), &xdamageBaseEvent
, &er
);
339 bool EvWidget::x11Event(XEvent
* event
)
342 if (event
->type
== xdamageBaseEvent
+XDamageNotify
) {
343 fb
->handleXDamage(event
);