1
0
mirror of https://github.com/KDE/krfb synced 2026-07-01 07:41:17 -07:00

X11 framebuffer implementation based on XDamage and XShm completed.

Still has some weirdness when updating large portions of the screen 

svn path=/trunk/KDE/kdenetwork/krfb/; revision=654248
This commit is contained in:
Alessandro Praduroux
2007-04-15 15:53:18 +00:00
parent 47c089f937
commit 6fd05b3a2a
12 changed files with 259 additions and 31 deletions

View File

@@ -3,6 +3,7 @@ project(krfb)
check_symbol_exists(rfbInitServer "rfb/rfb.h" HAVE_LIBVNCSERVER)
macro_bool_to_01(X11_Xdamage_FOUND HAVE_XDAMAGE)
macro_bool_to_01(X11_XShm_FOUND HAVE_XSHM)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-krfb.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-krfb.h )
include_directories(${CMAKE_CURRENT_BINARY_DIR}) # for config-krfb.h

View File

@@ -6,3 +6,6 @@
/* Define if XDamage is available */
#cmakedefine HAVE_XDAMAGE 1
/* Define if XShm is available */
#cmakedefine HAVE_XSHM 1

View File

@@ -183,6 +183,7 @@ void ConnectionController::handlePointerEvent(int bm, int x, int y)
void ConnectionController::handleClientGone()
{
emit clientDisconnected(this);
kDebug() << "client gone" << endl;
deleteLater();
}

View File

@@ -42,6 +42,7 @@ public:
Q_SIGNALS:
void sessionEstablished(QString);
void notification(QString, QString);
void clientDisconnected(ConnectionController *);
protected Q_SLOTS:
void dialogAccepted();

View File

@@ -10,7 +10,7 @@
#include "framebuffer.h"
#include "framebuffer.moc"
#include "config-krfb.h"
#include <config-krfb.h>
#include <QX11Info>
@@ -42,9 +42,11 @@ char * FrameBuffer::data()
return fb;
}
QVector< QRect > & FrameBuffer::modifiedTiles()
QList< QRect > FrameBuffer::modifiedTiles()
{
return tiles;
QList<QRect> ret = tiles;
tiles.clear();
return ret;
}
int FrameBuffer::width()
@@ -75,6 +77,7 @@ FrameBuffer * FrameBuffer::getFrameBuffer(WId id, QObject * parent)
}
#endif
return new QtFrameBuffer(id, parent);
}
int FrameBuffer::paddedWidth()
@@ -82,4 +85,12 @@ int FrameBuffer::paddedWidth()
return width() * depth() / 8;
}
void FrameBuffer::startMonitor()
{
}
void FrameBuffer::stopMonitor()
{
}

View File

@@ -12,7 +12,7 @@
#include <QObject>
#include <QRect>
#include <QVector>
#include <QList>
#include <QWidget>
#include <rfb/rfb.h>
@@ -32,11 +32,13 @@ public:
char * data();
QVector<QRect> &modifiedTiles();
virtual QList<QRect> modifiedTiles();
virtual int paddedWidth();
virtual int width();
virtual int height();
virtual int depth();
virtual void startMonitor();
virtual void stopMonitor();
virtual void getServerFormat(rfbPixelFormat &format);
@@ -45,7 +47,7 @@ protected:
WId win;
char *fb;
QVector<QRect> tiles;
QList<QRect> tiles;
};

View File

@@ -116,12 +116,13 @@ static void clipboardHook(char* str,int len, rfbClientPtr cl)
class KrfbServer::KrfbServerP {
public:
KrfbServerP() : fb(0), screen(0) {};
KrfbServerP() : fb(0), screen(0), numClients(0) {};
FrameBuffer *fb;
QList< QPointer<ConnectionController> > controllers;
rfbScreenInfoPtr screen;
bool running;
int numClients;
};
@@ -198,9 +199,8 @@ void KrfbServer::startListening()
while (d->running) {
foreach(QRect r, d->fb->modifiedTiles()) {
rfbMarkRectAsModified(screen, r.top(), r.left(), r.left() + r.width(), r.top() + r.height());
rfbMarkRectAsModified(screen, r.x(), r.y(), r.right(), r.bottom());
}
d->fb->modifiedTiles().clear();
rfbProcessEvents(screen, 100);
qApp->processEvents();
}
@@ -226,11 +226,16 @@ void KrfbServer::disconnectAndQuit()
enum rfbNewClientAction KrfbServer::handleNewClient(struct _rfbClientRec * cl)
{
ConnectionController *cc = new ConnectionController(cl, this);
if (d->numClients == 0) {
d->fb->startMonitor();
d->numClients++;
}
d->controllers.append(cc);
cc->setControlEnabled(KrfbConfig::allowDesktopControl());
connect(cc, SIGNAL(sessionEstablished(QString)), SIGNAL(sessionEstablished(QString)));
connect(cc, SIGNAL(clientDisconnected(ConnectionController *)),SLOT(clientDisconnected(ConnectionController *)));
return cc->handleNewClient();
}
@@ -273,5 +278,15 @@ bool KrfbServer::checkX11Capabilities() {
return true;
}
void KrfbServer::clientDisconnected(ConnectionController *cc)
{
kDebug() << "clients--: " << d->numClients << endl;
d->numClients--;
if (d->numClients == 0) {
d->fb->stopMonitor();
}
disconnect(cc, SIGNAL(clientDisconnected(ConnectionController)),this, SLOT(clientDisconnected(ConnectionController)));
}

View File

@@ -14,7 +14,7 @@
#include <rfb/rfb.h>
class FrameBuffer;
class ConnectionController;
/**
This class implements the listening server for the RFB protocol.
@@ -45,6 +45,7 @@ public Q_SLOTS:
void disconnectAndQuit();
void updateSettings();
void updatePassword();
void clientDisconnected(ConnectionController *);
private:
KrfbServer();

View File

@@ -23,9 +23,8 @@ QtFrameBuffer::QtFrameBuffer(WId id, QObject *parent)
{
fbImage = QPixmap::grabWindow(win).toImage();
fb = new char[fbImage.numBytes()];
QTimer *t = new QTimer(this);
t = new QTimer(this);
connect(t, SIGNAL(timeout()), SLOT(updateFrameBuffer()));
t->start(UPDATE_TIME);
}
@@ -103,3 +102,13 @@ int QtFrameBuffer::paddedWidth()
return fbImage.width() * 4;
}
void QtFrameBuffer::startMonitor()
{
t->start(UPDATE_TIME);
}
void QtFrameBuffer::stopMonitor()
{
t->stop();
}

View File

@@ -13,6 +13,7 @@
#include <QImage>
#include "framebuffer.h"
class QTimer;
/**
@author Alessandro Praduroux <pradu@pradu.it>
*/
@@ -29,13 +30,15 @@ public:
virtual int width();
virtual int paddedWidth();
virtual void getServerFormat(rfbPixelFormat& format);
virtual void startMonitor();
virtual void stopMonitor();
public Q_SLOTS:
void updateFrameBuffer();
private:
QImage fbImage;
QTimer *t;
};
#endif

View File

@@ -9,7 +9,8 @@
#include "x11framebuffer.h"
#include "x11framebuffer.moc"
#include "config-krfb.h"
#include <config-krfb.h>
#include <QX11Info>
#include <QApplication>
@@ -17,25 +18,47 @@
#include <KApplication>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#ifdef HAVE_XSHM
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#endif
class X11FrameBuffer::P {
public:
#ifdef HAVE_XDAMAGE
Damage damage;
#endif
#ifdef HAVE_XSHM
XShmSegmentInfo shminfo;
#endif
XImage *framebufferImage;
XImage *updateTile;
EvWidget *ev;
bool useShm;
int xdamageBaseEvent;
bool running;
};
X11FrameBuffer::X11FrameBuffer(WId id, QObject* parent)
:FrameBuffer(id, parent), d(new X11FrameBuffer::P)
{
#ifdef HAVE_XSHM
d->useShm = XShmQueryExtension(QX11Info::display());
kDebug() << "shm: " << d->useShm << endl;
#else
d->useShm = false;
#endif
d->running = false;
d->framebufferImage = XGetImage(QX11Info::display(),
id,
0,
@@ -44,7 +67,29 @@ X11FrameBuffer::X11FrameBuffer(WId id, QObject* parent)
QApplication::desktop()->height(),
AllPlanes,
ZPixmap);
if (d->useShm) {
#ifdef HAVE_XSHM
d->updateTile = XShmCreateImage(QX11Info::display(),
DefaultVisual( QX11Info::display(), 0 ),
d->framebufferImage->bits_per_pixel,
ZPixmap,
NULL,
&d->shminfo,
32,
32);
d->shminfo.shmid = shmget(IPC_PRIVATE,
d->updateTile->bytes_per_line * d->updateTile->height,
IPC_CREAT | 0777);
d->shminfo.shmaddr = d->updateTile->data = (char *)
shmat(d->shminfo.shmid, 0, 0);
d->shminfo.readOnly = False;
XShmAttach(QX11Info::display(), &d->shminfo);
#endif
} else {
;
}
kDebug() << "Got image. bpp: " << d->framebufferImage->bits_per_pixel
<< ", depth: " << d->framebufferImage->depth
<< ", padded width: " << d->framebufferImage->bytes_per_line
@@ -54,8 +99,6 @@ X11FrameBuffer::X11FrameBuffer(WId id, QObject* parent)
fb = d->framebufferImage->data;
#ifdef HAVE_XDAMAGE
d->ev = new EvWidget(this);
d->damage = XDamageCreate(QX11Info::display(), id, XDamageReportRawRectangles);
XDamageSubtract(QX11Info::display(),d->damage, None, None);
kapp->installX11EventFilter(d->ev);
#endif
}
@@ -66,7 +109,12 @@ X11FrameBuffer::~X11FrameBuffer()
XDestroyImage(d->framebufferImage);
#ifdef HAVE_XDAMAGE
kapp->removeX11EventFilter(d->ev);
XDamageDestroy(QX11Info::display(),d->damage);
#endif
#ifdef HAVE_XSHM
XShmDetach(QX11Info::display(), &d->shminfo);
XDestroyImage(d->updateTile);
shmdt(d->shminfo.shmaddr);
shmctl(d->shminfo.shmid, IPC_RMID, 0);
#endif
delete d;
}
@@ -132,25 +180,151 @@ void X11FrameBuffer::handleXDamage(XEvent * event)
QRect r(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
tiles.append(r);
XGetSubImage(QX11Info::display(),
win,
dev->area.x,
dev->area.y,
dev->area.width,
dev->area.height,
AllPlanes,
ZPixmap,
d->framebufferImage,
dev->area.x,
dev->area.y);
if (!dev->more) {
/*if (!dev->more) {
XDamageSubtract(QX11Info::display(),d->damage, None, None);
}
}*/
#endif
}
void X11FrameBuffer::cleanupRects() {
QList<QRect> cpy = tiles;
bool inserted = false;
tiles.clear();
// kDebug() << "before cleanup: " << cpy.size() << endl;
foreach (QRect r, cpy) {
if (tiles.size() > 0) {
for(int i = 0; i < tiles.size(); i++) {
// kDebug() << r << tiles[i] << endl;
if (r.intersects(tiles[i])) {
tiles[i] |= r;
inserted = true;
break;
// kDebug() << "merged into " << tiles[i] << endl;
}
}
if (!inserted) {
tiles.append(r);
// kDebug() << "appended " << r << endl;
}
} else {
// kDebug() << "appended " << r << endl;
tiles.append(r);
}
}
for(int i = 0; i < tiles.size(); i++) {
tiles[i].adjust(-30,-30,30,30);
if (tiles[i].top() < 0){
tiles[i].setTop(0);
}
if (tiles[i].left() < 0){
tiles[i].setLeft(0);
}
if (tiles[i].bottom() > d->framebufferImage->height) {
tiles[i].setBottom(d->framebufferImage->height);
}
if (tiles[i].right() > d->framebufferImage->width) {
tiles[i].setRight(d->framebufferImage->width);
}
}
// kDebug() << "after cleanup: " << tiles.size() << endl;
}
void X11FrameBuffer::acquireEvents() {
XEvent ev;
while (XCheckTypedEvent(QX11Info::display(), d->xdamageBaseEvent+XDamageNotify, &ev)) {
handleXDamage(&ev);
}
XDamageSubtract(QX11Info::display(),d->damage, None, None);
}
QList< QRect > X11FrameBuffer::modifiedTiles()
{
QList<QRect> ret;
if (!d->running) return ret;
kapp->processEvents(); // try to make sure every damage event goes trough;
cleanupRects();
QRect gl;
//d->useShm = false;
if (tiles.size() > 0) {
if (d->useShm) {
#ifdef HAVE_XSHM
foreach(QRect r, tiles) {
// kDebug() << r << endl;
gl |= r;
int y = r.y();
int x = r.x();
while (x < r.right() ) {
while (y < r.bottom() ) {
if (y+d->updateTile->height > d->framebufferImage->height) {
y = d->framebufferImage->height - d->updateTile->height;
}
if (x+d->updateTile->width > d->framebufferImage->width) {
x = d->framebufferImage->width - d->updateTile->width;
}
// kDebug() << "x: " << x << " (" << r.x() << ") y: " << y << " (" << r.y() << ") " << r << endl;
XShmGetImage(QX11Info::display(), win, d->updateTile, x, y, AllPlanes);
int pxsize = d->framebufferImage->bits_per_pixel / 8;
char *dest = fb + ((d->framebufferImage->bytes_per_line * y) + (x*pxsize));
char *src = d->updateTile->data;
for (int i = 0; i < d->updateTile->height; i++) {
memcpy(dest, src, d->updateTile->bytes_per_line);
dest += d->framebufferImage->bytes_per_line;
src += d->updateTile->bytes_per_line;
}
y += d->updateTile->height;
}
x += d->updateTile->width;
y = r.y();
}
}
#endif
} else {
foreach(QRect r, tiles) {
XGetSubImage(QX11Info::display(),
win,
r.left(),
r.top(),
r.width(),
r.height(),
AllPlanes,
ZPixmap,
d->framebufferImage,
r.left(),
r.top()
);
}
}
}
// kDebug() << "tot: " << gl << endl;
// kDebug() << tiles.size() << endl;
ret = tiles;
tiles.clear();
return ret;
}
void X11FrameBuffer::startMonitor()
{
d->running = true;
#ifdef HAVE_XDAMAGE
d->damage = XDamageCreate(QX11Info::display(), win, XDamageReportRawRectangles);
XDamageSubtract(QX11Info::display(),d->damage, None, None);
#endif
}
void X11FrameBuffer::stopMonitor()
{
d->running = false;
#ifdef HAVE_XDAMAGE
XDamageDestroy(QX11Info::display(),d->damage);
#endif
}
EvWidget::EvWidget(X11FrameBuffer * x11fb)
:QWidget(0), fb(x11fb)
{

View File

@@ -39,14 +39,21 @@ public:
~X11FrameBuffer();
virtual QList<QRect> modifiedTiles();
virtual int depth();
virtual int height();
virtual int width();
virtual int paddedWidth();
virtual void getServerFormat(rfbPixelFormat& format);
virtual void startMonitor();
virtual void stopMonitor();
void handleXDamage( XEvent *event);
private:
void cleanupRects();
void acquireEvents();
class P;
P * const d;
};